ActiveMQ是最目前流行的JMS实现,所以文章做了一个基于Spring+ActiveMQ的整合实例,其中不包括任何业务。
准备工具:
1、Apache ActiveMQ(因为我的jdk1.6,所以下的版本比较低)
下载地址:http://activemq.apache.org/activemq-590-release.html
2、Spring架包(见源码)
3、tomcat7.x
具体部署过程:
1、myeclipse新建一个web项目,解压下载好的压缩包,在根目录下有一个 activemq-all-5.9.0.jar
,把这个和spring的架包一起导入到项目中。
2、spring-mvc.xml和applicationContext.xml配置
spring-mvc.xml
<!-- 启用注解 -->
<mvc:annotation-driven />
<context:component-scan base-package="com.tang">
<!-- 只扫描controller,springmvc拦截 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
applicationContext.xml
<!-- 静态资源,不会被spring mvc拦截 -->
<mvc:resources location="/resources/" mapping="/resources/**"/>
<context:component-scan base-package="com.tang.mq">
<!-- 扫描包,除了controller注释的不扫描 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
3、ActiveMQ.xml配置
具体的配置大家看源码~~
<!-- ActiveMQ -->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="tcp://127.0.0.1:61616"
userName="admin" password="admin"/>
配置JMS的服务商,这里的实现就是ActiveMQ(ActiveMQ默认的端口是61616,用户名和密码都是admin)
<!-- spring对jms的配置 -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<!-- 配置jms的服务商 -->
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<!-- 和上面一样的 -->
<!-- <constructor-arg ref="amqConnectionFactory"></constructor-arg> -->
<!-- Session缓存数量 -->
<property name="sessionCacheSize" value="100" />
</bean>
ConnectionFactory是Spring用于创建到JMS服务器链接的,spring有多种ConnectionFactory,比较常见的有SingleConnectionFactory和CachingConnectionFactory。其中SingleConnectionFactory对于建立JMS服务器链接的请求会一直返回同一个链接,并且会忽略Connection的close方法调用。而CachingConnectionFactory继承了SingleConnectionFactory,所以有SingleConnectionFactory的所有功能,而且它可以缓存Session、MessageProducer和MessageConsumer。所以我们这里用了CachingConnectionFactory。
Spring提供的ConnectionFactory只是Spring用于管理ConnectionFactory的,所以上面的targetConnectionFactory就是JMS真正的提供者。
<!-- 消息生产者 start -->
<!-- 定义JmsTemplate的Queue类型 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 注入spring的ConnctionFactory -->
<constructor-arg ref="connectionFactory"/>
<!-- 非pub/sub模型(发布/订阅),即队列模式Queue -->
<property name="pubSubDomain" value="false" />
</bean>
<!-- 定义JmsTemplate的Topic类型 -->
<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 注入spring的ConnctionFactory -->
<constructor-arg ref="connectionFactory"/>
<!-- pub/sub模型(发布/订阅) -->
<property name="pubSubDomain" value="true" />
</bean>
<!-- 消息生产者 end -->
Spring为我们提供了JmsTemplate来帮助我们发送消息,同时我们还要知道消息要发送到哪里,即发送到哪个JMS服务商,所以<constructor-arg ref="connectionFactory"/>
就是来指定消息具体发送到哪里。ActiveMQ的JMS实现提供了两种类型的机制,其中一种是Queue,即P2P。P2P的特点是一条消息只有一个消费者,并且消息被消费了,那么就不存在消息队列中。还有一种是Topic,即pub/sub。pub/sub的特点就是一条消息可以有多个消费者,就是一条消息可以被多个消费者消费。
<!-- 消费监听器 start -->
<!-- 定义Queue的消费监听器 -->
<jms:listener-container destination-type="queue" container-type="default" connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="myqueue" ref="queueReceiver1"/>
<jms:listener destination="myqueue" ref="queueReceiver2"/>
</jms:listener-container>
<!-- 定义Topic的消费监听器 -->
<jms:listener-container destination-type="topic" container-type="default" connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="mytopic" ref="topicReceiver1"/>
<jms:listener destination="mytopic" ref="topicReceiver2"/>
</jms:listener-container>
<!-- 消费监听器 end -->
上面我们配置好了JMS服务商,配置好了消息的发送,那么消息怎么被接收呢?spring提供的方式就是监听器。配置监听器中我们需要知道从哪里取消息,所以需要知道connection-factory
,而destination="mytopic"
就是配置具体从哪里取消息。ref="topicReceiver1"
则是配置具体接收到消息后要怎么处理。public class TopicReceiver1 implements MessageListener
,要实现MessageListener
接口,这样才能监听消息。
4、代码解读
生产者:
@Component("queueSender")
public class QueueSender {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;
/**
* 向目的地发送
* @param destination
* @param message
*/
public void send(String destination, final String message){
jmsTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
// TODO Auto-generated method stub
return session.createTextMessage(message);
}
});
}
}
注入JmsTemplate,利用send()发送消息,send中需要一个MessageCreator对象。然后从session中创建一个message发送。
消费者:
@Component
public class QueueReceiver1 implements MessageListener{
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
try {
System.out.println("QueueReceiver1接收到消息:" + ((TextMessage) message).getText());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
实现MessageListener接口,从message中获取接收到的消息,打印。
5、启动ActiveMQ
找到解压activemq的目录,其中bin目录下有个activemq.bat
,双击运行。
启动成功!
ActiveMQ为我们提供了一个应用,可以查看具体的消息详情。http://localhost:8161/admin/,用户名和密码都是admin。
上面的Queues就是P2P模式的消息,Topics则就是pub/sub模式。
6、测试运行
从测试结果我们也可以看出,Queue(P2P)一条消息只有一个消费者可以消费,而Topic(pub/sub)则可以被多个消费者消费。
再看一下这个,发现Queue中确实多了一条记录。
以上就是spring这和ActiveMQ的具体部署过程。
对于ActiveMQ不熟悉的同学可以参考http://blog.csdn.net/jiuqiyuliang/article/details/46701559,“深入浅出JMS”系列文章。