Spring整合JMS-基于activeMQ实现(一)
JMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话我们可以在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。对于消息的传递有两种类型,一种是点对点的,即一个生产者和一个消费者一一对应;另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
安装AMQ博客:http://blog.csdn.net/liupeng_family/article/details/46728091
1.2 Spring整合JMS
<
dependencies
>
<
dependency
>
<
groupId
>
junit
</
groupId
>
<
artifactId
>
junit
</
artifactId
>
<
version
>
4.10
</
version
>
<
scope
>
test
</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring-context
</
artifactId
>
<
version
>
3.2.5.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring- jms
</
artifactId
>
<
version
>
3.2.5.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring-test
</
artifactId
>
<
version
>
3.2.5.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
org.springframework
</
groupId
>
<
artifactId
>
spring- web
</
artifactId
>
<
version
>
3.2.5.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
javax.annotation
</
groupId
>
<
artifactId
>
jsr250- api
</
artifactId
>
<
version
>
1.0
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
org.apache.activemq
</
groupId
>
<
artifactId
>
activemq-core
</
artifactId
>
<
version
>
5.7.0
</
version
>
</
dependency
>
</
dependencies
>
1.2.1 ActiveMQ准备
1.2.2 配置ConnectionFactory
Spring为我们提供多个ConnectionFactory,有SingleConnectionFactory和CacheConnectionFactory。
1、SingleConnectionFactory对于建立JMS服务器连接的请求会一直返回同一个连接,并且会忽略Connection的close方法调用
2、CachingConnectionFactory继承了SingleConnectionFactory,所以他拥有其所有功能,同时新增缓存功能,可以缓存Session、MessageProducer和MessageConsumer。
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
xmlns:aop
=
"http://www.springframework.org/schema/aop"
xmlns:tx
=
"http://www.springframework.org/schema/tx"
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:context
=
"http://www.springframework.org/schema/context"
xmlns:jms
=
"http://www.springframework.org/schema/jms"
xsi:schemaLocation
=
"
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd "
>
< bean id = "connectionFactory" class = "org.springframework.jms.connection.CachingConnectionFactory" >
< property name = "targetConnectionFactory" ><!-- 真正可以产生Connection的ConnectionFactory,由对应的JMS服务厂商提供 -->< bean class = "org.apache.activemq.ActiveMQConnectionFactory" >< property name = "brokerURL" >< value > tcp :// localhost :61616 </ value ><!-- failover://(${mq.address})?randomize=false & jms.useAsyncSend=true -->
</ property ></ bean ></ property >< property name = "sessionCacheSize" value = "1" /></ bean >
1.2.3 配置生产者
生产者负责产生消息并发送到JMS服务器,这通常对应的是我们的一个业务逻辑服务实现类。服务实现类利用Spring为我们提供的JmsTemplate,所以配置生产者其实最核心的就是配置进行消息发送的JmsTemplate。对于消息发送者而言,要知道消息往哪里发,为此,在定义JmsTemplate的时候需要注入一个Spring提供的ConnectionFactory对象。
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<
bean
id
=
"jmsTemplate"
class
=
"org.springframework.jms.core.JmsTemplate"
>
<
property
name
=
"connectionFactory"
ref
=
"connectionFactory"
></
property
>
<
property
name
=
"defaultDestinationName"
value
=
"subject"
></
property
>
<
property
name
=
"deliveryPersistent"
value
=
"true"
></
property
>
<
property
name
=
"pubSubDomain"
value
=
"false"
></
property
>
<!-- false p2p,true topic -->
<
property
name
=
"sessionAcknowledgeMode"
value
=
"1"
></
property
>
<
property
name
=
"explicitQosEnabled"
value
=
"true"
></
property
>
<
property
name
=
"timeToLive"
value
=
"604800000"
></
property
>
</
bean
>
1.2.4 配置队列
在真正利用JmsTemplate进行消息发送的时候,我们需要知道目的地(destination)。在JMS中存在Destination接口,它里面没有任何方法定义,用来做一个标识而已。当使用JmsTemplate进行消息发送的时候没有指定目的地会使用
默认的Destination。默认的Destination在定义JmsTemplate bean时候通过defaultDestination或者defaultDestinationName来进行注入。
在AMQ中存在两种类型的Destination,一种是点对点的ActiveMQQueue,另一个就是支持订阅/发布模式的ActiveMQTopic。
<!-- 配置Queue,队列目的地,其中value为Queue名称 -->
<
bean
id
=
"testQueue"
class
=
"org.apache.activemq.command.ActiveMQQueue"
>
<
constructor-arg
index
=
"0"
value
=
"queue.sys.liupeng.test.add"
/>
</
bean
>
<!-- 配置Topic,主题目的地,其中value为Topic名称<bean id="destination" class="org.apache.activemq.command.ActiveMQTopic"><constructor- arg index="0" value="topic.adapter.amq.destination" /></bean>-->
<!-- 注入AMQ的实现类属性(JmsTemplate和Destination) -->< bean id = "amqQueueSender" class = "com.tuniu.scc.purchase.plan.manage.core.amq.AMQQueueSender" >< property name = "jmsTemplate" ref = "jmsTemplate" ></ property ></ bean >
1.2.5 配置消费者
<!-- 消息监听器 -->
<
bean
id
=
"consumerMessageListener"
class
=
"com.liupeng.test.service.ConsumerMessageListener"
/>
<!-- 消息监听容器 -->
<
bean
id
=
"jmsContainer"
class
=
"org.springframework.jms.listener.DefaultMessageListenerContainer"
>
<
property
name
=
"connectionFactory"
ref
=
"connectionFactory"
/>
<
property
name
=
"destination"
ref
=
"testQueue"
/>
<!-- 消费者队列名称,修改 -->
<
property
name
=
"messageListener"
ref
=
"consumerMessageListener"
/>
</
bean
>
<!-- <jms:listener-container connection-factory="connectionFactory" destination-type="queue">
<jms:listener destination="${real.stock.info}" ref="consumerMessageListener" method="onMessage" />
</jms:listener-container> -->
1.2.6 生产消息
通过JmsTemplate来发送消息到对应的Destination
public
class
AMQQueueSender {
private JmsTemplate jmsTemplate ;/*** 发送消息* @param message :* @throws InterruptedException*/public void sendMessage(Destination destination, final String message) throws InterruptedException {System. out .println( "-----生产者发送消息-----" );System. out .println( "-----生产者发了一个消息:" +message);jmsTemplate .send(destination, new MessageCreator() {public Message createMessage(Session session) throws JMSException {return session.createTextMessage(message);}});}
public JmsTemplate getJmsTemplate() {return jmsTemplate ;}
public void setJmsTemplate(JmsTemplate jmsTemplate) {this . jmsTemplate = jmsTemplate;}}
1.2.7 消费消息
消费者通过Spring为我们封装的消息监听容器MessageListenerContainer接收消息,并把接收到的消息分发给真正的MessageListener进行处理。
每个消费者对应每个目的地都需要有对应的
MessageListenerContainer。对于该容器而言,需要知道监听哪个目的地、去哪里监听(监听哪个JMS服务器),这是通过配置MessageConnectionFactory的时候往里面注入一个ConnectionFactory来实现的。所以在配置一个
MessageListenerContainer的时候有三个属性必须指定,一个是从哪里监听的ConnectionFactory,一个是监听什么Destination,一个进行消息处理的MessageListener。Spring为我们提供了两种类型的
MessageListenerContainer,Simple
MessageListenerContainer和Default
MessageListenerContainer。
Simple
MessageListenerContainer会在一开始的时候就创建一个session和consumer,并且会使用标准的JMS MessageConsumer.setMessageListener()方法注册监听器让JMS提供者调用监听器的回调函数。它不会动态适应运行时需要和参与外部的事务管理,兼容性方面,非常接近于独立的JMS规范,但一般不兼容Java EE的JMS限制
Default
MessageListenerContainer会动态的适应运行时需要,能够参与外部事务管理,兼容Java EE
public
class
ConsumerMessageListener
implements
MessageListener{
public void onMessage(Message message) {//这里我们知道生产者发送的就是一个纯文本消息,所以这里可以直接进行强制转换,或者直接把onMessage方法的参数改成Message的子类TextMessageTextMessage textMessage = (TextMessage)message;System. out .println( "接收到一个纯文本消息" );try {System. out .println( "消息内容是:" + textMessage.getText());} catch (JMSException e) {e.printStackTrace();}}}
1.2.8 测试使用
@Resource
private
Destination
testQueue
;
@Resource
private
AMQQueueSender
amqQueueSender
;
@RequestMapping
(value =
"/liupeng/testAMQ"
, method = RequestMethod.
POST
)
public
void
test() {
System.
out
.println(
"开始发送"
);
try
{
amqQueueSender
.sendMessage(
testQueue
,
"消息1"
);
amqQueueSender
.sendMessage(
testQueue
,
"消息2"
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.
out
.println(
"---------"
);
}