SpringBoot2.0源码分析(二):整合ActiveMQ分析
SpringBoot具体整合ActiveMQ可参考:SpringBoot2.0应用(二):SpringBoot2.0整合ActiveMQ
ActiveMQ自动注入
当项目中存在javax.jms.Message和org.springframework.jms.core.JmsTemplate着两个类时,SpringBoot将ActiveMQ需要使用到的对象注册为Bean,供项目注入使用。一起看一下JmsAutoConfiguration类。
@Configuration
@ConditionalOnClass({ Message.class, JmsTemplate.class })
@ConditionalOnBean(ConnectionFactory.class)
@EnableConfigurationProperties(JmsProperties.class)
@Import(JmsAnnotationDrivenConfiguration.class)
public class JmsAutoConfiguration {
@Configuration
protected static class JmsTemplateConfiguration {
......
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
PropertyMapper map = PropertyMapper.get();
JmsTemplate template = new JmsTemplate(connectionFactory);
template.setPubSubDomain(this.properties.isPubSubDomain());
map.from(this.destinationResolver::getIfUnique).whenNonNull()
.to(template::setDestinationResolver);
map.from(this.messageConverter::getIfUnique).whenNonNull()
.to(template::setMessageConverter);
mapTemplateProperties(this.properties.getTemplate(), template);
return template;
}
......
}
@Configuration
@ConditionalOnClass(JmsMessagingTemplate.class)
@Import(JmsTemplateConfiguration.class)
protected static class MessagingTemplateConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(JmsTemplate.class)
public JmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {
return new JmsMessagingTemplate(jmsTemplate);
}
}
}
RabbitAutoConfiguration主要注入了jmsMessagingTemplate和jmsTemplate。
RabbitAutoConfiguration同时导入了RabbitAnnotationDrivenConfiguration,注入了jmsListenerContainerFactory。
消息发送
以下面的发送为例:
jmsMessagingTemplate.convertAndSend(this.queue, msg);
这个方法会先对消息进行转换,预处理,最终通过调用JmsTemplate的doSend实现消息发送的。
protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
throws JMSException {
Assert.notNull(messageCreator, "MessageCreator must not be null");
MessageProducer producer = createProducer(session, destination);
try {
Message message = messageCreator.createMessage(session);
doSend(producer, message);
if (session.getTransacted() && isSessionLocallyTransacted(session)) {
JmsUtils.commitIfNecessary(session);
}
}
finally {
JmsUtils.closeMessageProducer(producer);
}
}
首先创建一个MessageProducer的实例,接着将最初的org.springframework.messaging.Message转换成javax.jms.Message,再将消息委托给producer进行发送。
消息接收
先看一个消费的事例:
@Component
public class Consumer {
@JmsListener(destination = "sample.queue")
public void receiveQueue(String text) {
System.out.println(text);
}
}
SpringBoot会去解析@JmsListener,具体实现在JmsListenerAnnotationBeanPostProcessor的postProcessAfterInitialization方法。
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
Map<Method, Set<JmsListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
(MethodIntrospector.MetadataLookup<Set<JmsListener>>) method -> {
Set<JmsListener> listenerMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
method, JmsListener.class, JmsListeners.class);
return (!listenerMethods.isEmpty() ? listenerMethods : null);
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(bean.getClass());
}
else {
annotatedMethods.forEach((method, listeners) ->
listeners.forEach(listener ->
processJmsListener(listener, method, bean)));
}
}
return bean;
}
SpringBoot根据注解找到了使用了@JmsListener注解的方法,当监听到ActiveMQ收到的消息时,会调用对应的方法。来看一下具体怎么进行listener和method的绑定的。
protected void processJmsListener(JmsListener jmsListener, Method mostSpecificMethod, Object bean) {
Method invocableMethod = AopUtils.selectInvocableMethod(mostSpecificMethod, bean.getClass());
MethodJmsListenerEndpoint endpoint = createMethodJmsListenerEndpoint();
endpoint.setBean(bean);
endpoint.setMethod(invocableMethod);
endpoint.setMostSpecificMethod(mostSpecificMethod);
endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory);
endpoint.setEmbeddedValueResolver(this.embeddedValueResolver);
endpoint.setBeanFactory(this.beanFactory);
endpoint.setId(getEndpointId(jmsListener));
endpoint.setDestination(resolve(jmsListener.destination()));
if (StringUtils.hasText(jmsListener.selector())) {
endpoint.setSelector(resolve(jmsListener.selector()));
}
if (StringUtils.hasText(jmsListener.subscription())) {
endpoint.setSubscription(resolve(jmsListener.subscription()));
}
if (StringUtils.hasText(jmsListener.concurrency())) {
endpoint.setConcurrency(resolve(jmsListener.concurrency()));
}
JmsListenerContainerFactory<?> factory = null;
String containerFactoryBeanName = resolve(jmsListener.containerFactory());
if (StringUtils.hasText(containerFactoryBeanName)) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
try {
factory = this.beanFactory.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanInitializationException("Could not register JMS listener endpoint on [" +
mostSpecificMethod + "], no " + JmsListenerContainerFactory.class.getSimpleName() +
" with id '" + containerFactoryBeanName + "' was found in the application context", ex);
}
}
this.registrar.registerEndpoint(endpoint, factory);
}
先设置endpoint的相关属性,再获取jmsListenerContainerFactory,最后将endpoint注册到jmsListenerContainerFactory。
本篇到此结束,如果读完觉得有收获的话,欢迎点赞、关注、加公众号【贰级天災】,查阅更多精彩历史!!!
SpringBoot2.0源码分析(二):整合ActiveMQ分析的更多相关文章
- jmeter4.0 源码编译 二次开发
准备: 1.jmeter4.0源码 - apache-jmeter-4.0_src.zip 2.IDE Eclipse - Oxygen.3 Release (4.7.3) 3.JDK - 1.8.0 ...
- SpringBoot2.0源码分析(三):整合RabbitMQ分析
SpringBoot具体整合rabbitMQ可参考:SpringBoot2.0应用(三):SpringBoot2.0整合RabbitMQ RabbitMQ自动注入 当项目中存在org.springfr ...
- SpringBoot2.0源码分析(一):SpringBoot简单分析
SpringBoot2.0简单介绍:SpringBoot2.0应用(一):SpringBoot2.0简单介绍 本系列将从源码角度谈谈SpringBoot2.0. 先来看一个简单的例子 @SpringB ...
- SpringBoot2.0源码分析(四):spring-data-jpa分析
SpringBoot具体整合rabbitMQ可参考:SpringBoot2.0应用(四):SpringBoot2.0之spring-data-jpa JpaRepositories自动注入 当项目中存 ...
- vue2.0 源码解读(二)
小伞最近比较忙,阅读源码的速度越来越慢了 最近和朋友交流的时候,发现他们对于源码的目录结构都不是很清楚 红色圈子内是我们需要关心的地方 compiler 模板编译部分 core 核心实现部分 ent ...
- AFNetworking2.0源码解析<二>
本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization. AFURLRequestSerialization用于帮助构建NSURLReque ...
- [Android FrameWork 6.0源码学习] Window窗口类分析
了解这一章节,需要先了解LayoutInflater这个工具类,我以前分析过:http://www.cnblogs.com/kezhuang/p/6978783.html Window是Activit ...
- webpack4.0源码解析之esModule打包分析
入口文件index.js采用esModule方式导入模块文件,非入口文件index1.js分别采用CommonJS和esmodule规范进行导出. 首先,init之后创建一个简单的webpack基本的 ...
- AFNetworking (3.1.0) 源码解析 <二>
这次讲解AFHTTPSessionManager类,按照顺序还是先看.h文件,注释中写到AFHTTPSessionManager是AFURLSessionManager的子类,并且带有方便的HTTP请 ...
随机推荐
- CRM中QueryDict和模型表知识补充
CRM中QueryDict和模型表知识补充 1.QueryDict的用法 request.GET的用法:1.在页面上输入:http://127.0.0.1:8000/index/print(reque ...
- Linux下所有命令失效的解决方法
今天在设置环境变量时,一不小心,设置错了,系统中的所有命令全部失效了,可把我急坏了,下面用一条命令可解决: 解决办法:重新设置环境变量PATH export PATH=/usr/sbin:/usr/b ...
- Python:每日一题001
题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? **程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 个人解 ...
- 重读<<大话设计模式>>读书笔记一
面向对象编程几大原则: 1.简单工厂模式 解读:根据不同条件,动态创建合适的对象. 目的: 解决对象创建问题 举例: 计算器根据不同情况,创建适合的对象来处理数据. 2.策略模式 解读:也是根据不同的 ...
- rabbit初学之连接测试2
com.rabbitmq.client.ShutdownSignalException: connection error 发现,port是5672,不是15672(15672是后台管理平台的端口)
- Java 装箱和拆箱
1.装箱机制 基础类型引用到其包装类型,这样就可以调用其各种方法. 例如,我们声明: Integer a = 1; 其在编译过程中会自动解释成: Integer a = Integer.valueOf ...
- cms后台管理
{项目名称:cms}-后台管理系统 项目阶段性总结报告 1 项目信息 开发工具:eclinpse,mysql,foxmail 使用到的技术:springMVC,springJDBC,maven,fre ...
- sql pivot(行转列) 和unpivot(列转行)的用法
1.PIVOT用法(行转列) select * from Table_Score as a pivot (sum(score) for a.name in ([语文],[数学],[外语],[文综],[ ...
- redis 分布式读写锁
http://zhangtielei.com/posts/blog-redlock-reasoning.html 链接里这篇 blog 讨论了 redis 分布式锁的实现以及安全性 我要参考 基于单R ...
- 使用广播-BroadcastReceiver最详细解析
女孩:BroadcastReceiver是什么呀? 男孩:Broadcast是广播的意思,在Android中应用程序之间的传输信息的机制,BroadcastReceiver是接收广播通知的组件,广播和 ...