Sping+ActiveMQ整合
通过前一篇《ActiveMQ简述》大概对ActiveMQ有了一个大概的认识。本篇所阐述的是怎样通过Spring继承ActiveMQ进而更有效、更灵活的运用ActiveMQ.
Spring和ActiveMQ整合须要在项目中包括下面这几个jar包(缺一不可):activeio-core-3.1.4.jar,activemq-all-5.13.2.jar,activemq-pool-5.13.2.jar。commons-pool2-2.4.2.jar,这些jar能够在ActiveMQ的安装包中的/lib/optional/下找到,或者从这里下载。
配置ConnectionFactory
ConnectionFactory是用于产生到JMSserver的链接的,Spring为我们提供了多个ConnectionFactory,有SingleConnectionFactory和CachingConnectionFactory。
SingleConnectionFactory对于建立JMSserver链接的请求会一直返回同一个链接,而且会忽略Connection的close方法调用。
CachingConnectionFactory继承了SingleConnectionFactory,所以它拥有SingleConnectionFactory的全部功能,同一时候它还新增了缓存功能。能够缓存Session, MessageProducer和MessageConsumer。
Spring提供的ConnectionFactory仅仅是Spring用于管理ConnectionFactory的,真正产生到JMSserver链接的ConnectionFactory还得是JMS服务厂商提供的,而且须要把它注入到Spring提供的ConnectionFactory中。这里使用ActiveMQ提供的ConnectionFactory,所以定义例如以下(10.10.195.187是博主的測试ip地址):
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://10.10.195.187:61616" />
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
</bean>
ActiveMQ为我们提供了一个PooledConnectionFactory。通过往里面注入一个ActiveMQConnectionFactory能够用来将Connection, Session和MessageProducer池化,这样能够大大的降低我们的资源消耗。当使用PooledConnectionFactory时。我们在定义一个ConnectionFactory时这样定义:
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://10.10.195.187:61616" />
</bean>
<bean id="poolConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" >
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="maxConnections" value="10"/>
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="poolConnectionFactory"/>
</bean>
这里也能够去掉spring提供的SingleConnectionFactory,相似这样:
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://10.10.195.187:61616" />
</bean>
<bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" >
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="maxConnections" value="10"/>
</bean>
配置消息发送(生产)者
配置好ConnectionFactory之后我们就须要配置生产者。生产者负责生产消息并发送到JMSserver。这通常相应的是我们的一个业务逻辑服务实现类。可是我们的服务实现类是怎么进行消息的发送的呢?这一般是利用Spring为我们提供的JmsTemplate类来实现,所以配置生产者事实上最核心的就是配置进行消息发送的JmsTemplate。
对于消息发送者而言,它在发送消息的时候要知道自己该往哪里发。为此,我们在定义JmsTemplate的时候须要往里面注入一个Spring提供的ConnectionFactory对象。
spring配置文件里加入:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="poolConnectionFactory"/>
</bean>
在Java相关处理文件里加入(这里用的是@Inject注解,当然也能够用@Autowired):
@Inject
@Named("jmsTemplate")
private JmsTemplate jmsTemplate;
这样就能够通过jmsTemplate对象来处理相关信息。譬如:
jmsTemplate.convertAndSend("sqlQueue",sql);
真正利用JmsTemplate进行消息发送的时候,我们须要知道消息发送的目的地,即Destination。在Jms中有一个用来表示目的地的Destination接口,它里面没有不论什么方法定义,仅仅是用来做一个标志而已。
当我们在使用JmsTemplate进行消息发送时没有指定destination的时候将使用默认的Destination。
默认Destination能够通过在定义jmsTemplate bean对象时通过属性defaultDestination或defaultDestinationName来进行诸如。defaultDestinationName对于的就是一个普通字符串。在ActiveMQ中实现了两种类型的Destination。一个是点对点的ActiveMQQueue,还有一个就是支持订阅-公布模式的ActiveMQTopic。
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>sqlQueue</value>
</constructor-arg>
</bean>
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg>
<value>topic</value>
</constructor-arg>
</bean>
对面上面的那个样例能够在Java程序中加入:
@Inject
@Named("queueDestination")
private Destination queueDestination;
进而【jmsTemplate.convertAndSend(“sqlQueue”,sql);】能够改为【jmsTemplate.convertAndSend(queueDestination,sql);】
也能够这样改动jmsTemplate:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestination" ref="queueDestination"/>
</bean>
或者:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestinationName" value="sqlQueue"/>
</bean>
进而在java程序中这样调用:jmsTemplate.convertAndSend(sql);
配置消息接收(消费)者
生产者往指定目的地Destination发送消息后,接下来就是消费者对指定目的地的消息进行消费了。
那么消费者是怎样知道有生产者发送消息到指定目的地Destination了呢?这是通过Spring为我们封装的消息监听容器MessageListenerContainer实现的,它负责接收信息,并把接收到的信息分发给真正的MessageListener进行处理。
每一个消费者相应每一个目的地都须要有相应的MessageListenerContainer。
对于消息监听容器而言,除了要知道监听哪个目的地之外。还须要知道到哪里去监听。也就是说它还须要知道去监听那个JMSserver,这是通过在配置MessageConnectionFactory的时候往里面注入一个ConnectionFactory来实现的。
所以我们在配置一个MessageListenerContainer的时候有三个属性必须指定,一个是表示从哪里监听的ConnectionFactory,一个是表示监听什么的Destination。一个是接收到消息以后进行消息处理的MessageListener.
Spring为我们听过了两种类型的MessageListenerContainer:SimpleMessageListenerContainer和DefaultMessageListenerContainer。MessageListenerContainer:SimpleMessageListenerContainer会在一開始的时候就创建一个会话Session和消费者Consumer,而且会适用标准的JMS的MessageConsumer.setMessageListener()方法注冊监听器让JMS提供调用监听器的回调函数。
它不会动态的适应执行时须要和參与外部的事务管理。兼容性方面。它很接近于独立的JMS规范。但一般不兼容J2EE的JMS限制。大多数情况下,我们还是使用DefaultMessageListenerContainer。跟MessageListenerContainer:SimpleMessageListenerContainer想比。它会动态的适应执行时的需求。而且能够參与外部的事务管理。
它很好的平衡了JMS提供者要求低,先进功能如事务參与和兼容J2EE环境。
spring配置文件里加入:
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>sqlQueue</value>
</constructor-arg>
</bean>
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="poolConnectionFactory" />
<property name="messageListener" ref="jmsQueueReceiver" />
<property name="destination" ref="queueDestination" />
</bean>
当中的jmsQueueReceiver代码例如以下:
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.stereotype.Component;
@Component("jmsQueueReceiver")
public class JmsQueueReceiver implements MessageListener
{
@Override
public void onMessage(Message messgae)
{
if(messgae instanceof TextMessage)
{
TextMessage textMessage = (TextMessage) messgae;
try
{
String text = textMessage.getText();
System.out.println("######################["+text+"]######################");
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}
}
事务管理
Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理。
这将同意JMS应用利用Spring的事务管理特性。JmsTransactionManager在执行本地资源事务管理时将从指定的ConnectionFactory绑定一个ConnectionFactory/Session这种配对到线程中。JmsTemplate会自己主动检測这种事务资源,并对他们进行相应的操作。
在J2EE环境中,ConnectionFactory会池化Connection和Session,这样这些资源将会在整个事务中被有效地反复利用。在一个独立的环境中,使用Spring的SingleConnectionFactory时全部的事务将公用一个Connection,可是每一个事务将保留自己独立的Session.
JmsTemplate能够利用JtaTransactionManager和能够进行分布式的JMS ConnectionFactory处理分布式事务。
在Spring整合JMS的应用中,假设我们要进行本地的事务管理的话很easy,仅仅须要在定义对于的消息监听容器时指定其sessionTransacted属性为true(默觉得false):
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="messageListener" ref="jmsQueueReceiver" />
<property name="destination" ref="queueDestination" />
<property name="sessionTransacted" value="true"/>
</bean>
这样JMS在进行消息监听的时候就会进行事务控制,当在接收消息时监听器执行失败时JMS就会对接收到的消息进行回滚。
这里须要注意的是对于其它操作如数据库等訪问不属于该事务控制。
能够在JmsQueueReceiver中改动一下代码从而检測到发送异常时是否会进行事务回滚:
@Component("jmsQueueReceiver")
public class JmsQueueReceiver implements MessageListener
{
@Override
public void onMessage(Message messgae)
{
if(messgae instanceof TextMessage)
{
TextMessage textMessage = (TextMessage) messgae;
try
{
String text = textMessage.getText();
System.out.println("######################["+text+"]######################");
if(true)
{
throw new RuntimeException("Error");
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}
}
你能够通过向Destination发送一条信息,通过JmsQueueReceiver处理后。发送异常进而事务混滚。能够通过http://10.10.195.187:8161/admin/queues.jsp查看相关信息(ip地址是博主的ActiveMQserver所在id,依据实际情况改动)。
假设想要接收消息和数据库訪问处于同一事务中,那么我们就能够配置一个外部的事务管理同一时候配置一个支持外部事务管理的消息监听容器(如DefaultMessageListenerContainer)。要配置这样一个參与分布式事务管理的消息监听容器,我们能够配置一个JtaTransactionManager。当然底层的JMS ConnectionFactory须要能够支持分布式事务管理,并正确地注冊我们的JtaTransactionManager。这样消息监听器进行消息接收和相应的数据库訪问就会处于同一数据库控制下,当消息接收失败或数据库訪问失败都会进行事务回滚操作。
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="messageListener" ref="jmsQueueReceiver" />
<property name="destination" ref="queueDestination" />
<property name="sessionTransacted" value="true"/>
<property name="transactionManager" ref="jtaTransactionManager"/>
</bean>
<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
当给小时监听容器指定了transactionManager时,消息监听容器将忽略sessionTransacted的值。
到这里大概的Spring+ActiveMQ整合告一段落。全部代码经博主亲測,确保有效性及正确性。
如有疑问。可在下方留言。
參考资料:
1. Spring整合JMS(一)——基于ActiveMQ实现
2. Spring+ActiveMQ+Mysql 配置JMS
3. ActiveMQ简述
Sping+ActiveMQ整合的更多相关文章
- 深入浅出JMS(四)--Spring和ActiveMQ整合的完整实例
第一篇博文深入浅出JMS(一)–JMS基本概念,我们介绍了JMS的两种消息模型:点对点和发布订阅模型,以及消息被消费的两个方式:同步和异步,JMS编程模型的对象,最后说了JMS的优点. 第二篇博文深入 ...
- JMS【四】--Spring和ActiveMQ整合的完整实例
第一篇博文JMS[一]--JMS基本概念,我们介绍了JMS的两种消息模型:点对点和发布订阅模型,以及消息被消费的两个方式:同步和异步,JMS编程模型的对象,最后说了JMS的优点. 第二篇博文JMS[二 ...
- Spring Boot入门 and Spring Boot与ActiveMQ整合
1.Spring Boot入门 1.1什么是Spring Boot Spring 诞生时是 Java 企业版(Java Enterprise Edition,JEE,也称 J2EE)的轻量级代替品.无 ...
- ActiveMQ整合spring、同步索引库
1. Activemq整合spring 1.1. 使用方法 第一步:引用相关的jar包. <dependency> <groupId>org.springframework ...
- JAVAEE——宜立方商城09:Activemq整合spring的应用场景、添加商品同步索引库、商品详情页面动态展示与使用缓存
1. 学习计划 1.Activemq整合spring的应用场景 2.添加商品同步索引库 3.商品详情页面动态展示 4.展示详情页面使用缓存 2. Activemq整合spring 2.1. 使用方法 ...
- Spring和ActiveMQ整合的完整实例
Spring和ActiveMQ整合的完整实例 前言 这篇博文,我们基于Spring+JMS+ActiveMQ+Tomcat,做一个Spring4.1.0和ActiveMQ5.11.1整合实例,实现了 ...
- 淘淘商城项目_同步索引库问题分析 + ActiveMQ介绍/安装/使用 + ActiveMQ整合spring + 使用ActiveMQ实现添加商品后同步索引库_匠心笔记
文章目录 1.同步索引库问题分析 2.ActiveM的介绍 2.1.什么是ActiveMQ 2.2.ActiveMQ的消息形式 3.ActiveMQ的安装 3.1.安装环境 3.2.安装步骤 4.Ac ...
- Spring Boot与ActiveMQ整合
Spring Boot与ActiveMQ整合 1使用内嵌服务 (1)在pom.xml中引入ActiveMQ起步依赖 <dependency> <groupId>org.spri ...
- ActiveMQ之三--JMS-Spring和ActiveMQ整合的完整实
这篇博文,我们基于Spring+JMS+ActiveMQ+Tomcat,做一个Spring4.1.0和ActiveMQ5.11.1整合实例,实现了Point-To-Point的异步队列消息和PUB/S ...
随机推荐
- PHP——注册页面,审核页面,登录页面:加Session和Cookie
实现效果: 用户注册信息,管理员核对信息审核通过后,可实现注册的用户名和密码的成功登陆,利用session和cookie获取用户信息并且不能跳过登录页面直接进入主页面 1.Session存储在服务器可 ...
- Spider Studio 新版本 (20140225) - 设置菜单调整 / 提供JQueryContext布局相关的方法
这是年后的第一个新版本, 包含如下: 1. 先前去掉的浏览器设置功能又回来了! 说来惭愧, 去掉了这两个功能之后发现浏览经常会被JS错误打断, 很不方便, 于是乎又把它们给找回来了. :) 2. 为J ...
- Linux系统查看公网IP地址
curl members.3322.org/dyndns/getip
- ti8168平台的tiler memory
DM8168 DMM/TILER简介 1.概述 如图4-1,DMM定位在SDRAM控制器的前端,是所有initiator产生的内存存取的接口. 动态内存管理器DMM,是一个专门的管理模块,广义上说,包 ...
- php -- session会话
PHP Sessions PHP session 变量用于存储关于用户会话(session)的信息,或者更改用户会话(session)的设置.Session 变量存储单一用户的信息,并且对于应用程序中 ...
- 【BZOJ】1630: [Usaco2007 Demo]Ant Counting(裸dp/dp/生成函数)
http://www.lydsy.com/JudgeOnline/problem.php?id=1630 题意,给你n种数,数量为m个,求所有的数组成的集合选长度l-r的个数 后两者待会写.. 裸dp ...
- RabbitMQ组成及原理介绍-3
rabbitmq作为成熟的企业消息中间件,实现了应用程序间接口调用的解耦,提高系统的吞吐量. 1.RabbitMQ组成 是由 LShift 提供的一个 Advanced Message Queuing ...
- loadimage1();有问题
f.Read(pBuffer, nSize)不能少,少了虽然能读进去数据但是不能显示成图片,可能原因是存进的数据并不是图片数据! 输入图片测试,但是没有CFile先Open再Read
- C# 笔记 Func<TResult> 委托、Action<T> 委托
https://blog.csdn.net/wanglui1990/article/details/79303894 Func<ΤResult> 委托:代理(delegate)一个返回类型 ...
- 剑指 offer set 22 数组中的逆序数
总结 1. 题目为归并排序的变形, 不过我完全没想到 2. 在归并排序进行字符组 merge 时, 统计逆序数. merge 后, 两个子数组是有序的了, 下次再 merge 的时候就能以 o(n) ...