JmsListener注解解析

JMS 消息分发送消息和接收消息两种功能,发送消息很简单,注入 Jms Template 到对应的Bean 中即可使用。接收消息则需要使用@JmsListener 注解。

先看一下发送消息的官方示例。

@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this. jmsTemplate = jmsTemplate;
}

将 JmsTemplate 注入 MyBean 中,便可在该类的其他方法中使用 JmsTemplate 来发送消息了。

接收消息的官方代码示例如下。

@Component
public class MyBean
@JmsListener(destination = " someQueue")
public void processMessage(String content) {
// ...
}
}

当 JMS 的基础构件都完成初始化之后,可以使用@JmsListener 注释任何 Bean 来创建侦听器端点,就像上面的示例一样。

@JmsListener 注解是由 Spring 提供的,它位于 spring-jms 包下。 Spring 会对注解了@JmsListener 的 方 法 进 行 处 理 。 在 这 一 过 程 中 主 要 使 用 到 同 一 包 下 的
JmsListenerAnnotation-BeanPostProcessor 类。该类中相关解析代码如下。

@Override
public object postProcessAfterInitialization(0bject bean, String beanName )
throws
BeansException
if (bean instanceof AopInfrastructureBean| bean instanceof JmsListener-
ContainerFactory|I
bean instanceof JmsListenerEndpointRegistry) {
//忽略诸如作用域代理之类的 AOP 基础结构
return bean;
//通过工具类 AopProxyUtils 获取最终的 Class 对象
Class<?> targetClass = AopProxyUtils . ultimateTargetClass(bean);//如果该目标 Class 不包含在 nonAnnotatedClasses(没有被炷解的类)
//并且目标 Class 为基 FJmsListener 的候选类
if (!this . nonAnnotatedClasses . contains(targetClass) &&
AnnotationUtils. isCandidateClass(targetClass, JmsListener.class)) {
//获取该类炷解有 Jmslistener 的方法集合
Map<Method, Set<JmsListener>> annotatedMethods = MethodIntrospector.
selec tMethods(targetClass,
(MethodIntrospector . MetadataLookup<Set<Jmslistener>>) met
hod -> {
Set<JmsListener> listenerMethods = AnnotatedE lementUtil
getMergedRepeatableAnnotations (
method, JmsListener.class, JmsL isteners. class);
return ( !listenerMethods . isEmpty() ? listenerMethods : nu
11);
});
if (annotatedMethods . isEmpty()) {
//该类方法为空,则将该类放入 nonAnnotatedClasses 中
this . nonAnnotatedClasses . add(targetClass);
else
/如果方法集合不为空, 则遍历方法集合并调用 processJmsL istener 方法进行后续
处理
annotatedMethods . forEach( (method, listeners)- >
listeners. forEach(listener -> processJmslisten
er(listener, method,
bean)));
return bean;
}

在上述代码中,核心的处理流程就是通过 Bean 获取最终符合条件的 Class 对象,然后获取该 Class 对象中被@JmsListener 注解的方法集合,遍历调用 processJmsListener 方法进行对应的注册操作。

在 processJmsListener 方 法中主要就是创建并初始化 MethodJmsListenerEndpoint 对象,同时创建了
JmsListenerContainerFactory 对象,然后通过 JmsListenerEndpointRegistrar的 registerEndpoint 方法将其进行注册到 JmsListenerContainerFactory 中。

因此,在代码中通过注解@JmsListener 便可进行消息的接收了。processJmsListener 部分代码如下。

protected void processJmsListener(JmsListener jmsListener, Method mostScific-Method, object bean) {
Method invocableMethod = AopUtils . selectInvocableMethod (mostSpecificMetho
d, bean. getClass());
MethodImsListenerEndpoint endpoint = createMethodImslistenerEndpoint();
endpoint. setBean(bean);
// ... 省略大量 set 方法
//创建 JmsL istenerContainerFactory
JmsListenerContainerFactory<?> factory = null;
String containerFactoryBeanName = resolve ( jmsL istener. containerFactory
());
if (StringUtils . hasText(containerFactoryBeanName)) {
Assert. state (this. beanFactory != null, "BeanFactory must be set to obta
container factory by bean name") ;
try
factory = this. beanFactory . getBean(containerF actoryBeanN
ame, JmsL istener-
ContainerFactory.clas
s);
} catch (NoSuchBeanDefinitionException ex) {
//通过 JmsL istenerEndpointRegistrar 进行注册
this . registrar. registerEndpoint(endpoint, factory);
}

默认情况下,当使用了@JmsListener 注解,而又没有自定义 JmsL istenerContainer-Factory时,Spring Boot 会自动创建一个默认的对象。

如果想创建多个
JmsListenerContainerFactory,可使用 Spring Boot 提供的DefaultJmsListenerContainerFactoryConfigurer 来创建,示例代码如下。

@Configuration
static class JmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
configurer . configure(factory, connectionFactory());
factory. setMessageConverter (myMessageConverter());
return factory;}
}

上 面 代 码 定 义 完
JmsListenerContainerFactory 之 后 , 在 @JmsListener 注 解 中 指 定

containerFactory 为对应的 Factory 名字(myFactory) 即可。

关于@JmsListener 的使用及原理,我们就讲到这里。

小结

本章重点分析了 Spring Boot 中 JMS 和 ActiveMQ 的自动配置。ActiveMQ 很 好地实现了JMS 协议,同时又可以很方便地进行定制化实现。针对 JMS 的注解部分,Spring Boot 也提供了专门的自动配置类
JmsAnnotationDrivenConfiguration 进行一系列的默认配置 ,本章并未进行讲解,读者朋友可自行阅读。而关于其他协议的自动配置实现基本相似,大家可进-步查看相关源代码。

本文给大家讲解的内容是SpringBoot消息源码解析:JmsListener注解解析

  1. 下篇文章给大家讲解的是SpringBootCache源码解析:Cache自动配置;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐