A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

Spring 实现远程访问详解——jms和activemq(a123demi)                       
                                                        前几章我们分别利用spring rmi、httpinvoker、httpclient、webservice技术实现不同服务器间的远程访问。本章我将通过spring jms和activemq实现单Web项目服务器间异步访问和多Web项目服务器间异步访问。
一.  简介1.      什么是Apache ActiveMqApache ActiveMq是最流行和最强大的开源消息和集成服务器。同时Apache ActiveMq是速度快,支持多种跨语言客户端和协议,同时配有易于使用的企业集成模式和优秀的特性,并且支持JMS1.1和J2EE1.4。具体特性见官网:http://activemq.apache.org/
2.      什么是JMSJMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话我们可以在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。
JMS 支持两种消息传递模型:
点对点(point-to-point,简称 PTP)
发布/订阅(publish/subscribe,简称 pub/sub)。
这两种消息传递模型非常相似,但有以下区别:
PTP 消息传递模型规定了一条消息只能传递给一个接收方。 采用javax.jms.Queue表示。Spring配置类型destination-type="queue"。
Pub/sub 消息传递模型允许一条消息传递给多个接收方。采用javax.jms.Topic表示。Spring配置类型destination-type="topic"。
二.  单服务器异步访问3.      Spring 整合JMS和ActiveMq流程1)      下载和部署ActiveMq服务器
2)      Spring jms和activemq相关依赖引入
3)      Spring整合activemq配置
4)      定义消息发布者(生产者)
5)      定义消息订阅者(消费者)
6)      Spring mvc配置
7)      实例测试
4.      Spring整合JMS和ActiveMq具体实现1)      下载和部署ActiveMq服务器下载地址:
http://activemq.apache.org/2016/03/07/apache-activemq-5132-released.html
解压下载文件,假如我保存在D盘根目录,找到目录apache-activemq-5.13.2\bin\win64下的activemq.bat,启动activemq服务。
2)      Spring jms和activemq相关依赖<!-- xbean如<amq:connectionFactory /> -->       <dependency>           <groupId>org.apache.xbean</groupId>           <artifactId>xbean-spring</artifactId>           <version>3.16</version>       </dependency>       <!-- Active MQ -->       <dependency>           <groupId>org.apache.activemq</groupId>           <artifactId>activemq-all</artifactId>           <version> 5.13.1</version>     </dependency><dependency>           <groupId>org.springframework</groupId>           <artifactId>spring-jms</artifactId>           <version> 4.2.0.RELEASE</version>     </dependency>
3)      Application-context-jms中配置jms和activemq注意头部信息需要引入jms和activemq


具体配置如下:
<?xml version="1.0"encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:amq="http://activemq.apache.org/schema/core"    xmlns:jms="http://www.springframework.org/schema/jms"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd        http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-3.2.xsd       http://activemq.apache.org/schema/core       http://activemq.apache.org/schema/core/activemq-core-5.9.0.xsd       http://www.springframework.org/schema/jms       http://www.springframework.org/schema/jms/spring-jms-4.0.xsd">     <description>application-context-activemqconfig</description>    <!-- activemq -->    <amq:connectionFactory id="amqConnectionFactory"       brokerURL="tcp://localhost:61616" userName="admin" password="admin"/>    <bean id="connectionFactory"       class="org.springframework.jms.connection.CachingConnectionFactory">       <constructor-arg ref="amqConnectionFactory"/>       <property name="sessionCacheSize"value="100" />    </bean>    <!-- ====Producer side start==== -->    <!-- 定义JmsTemplate的Queue类型 -->    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">        <constructor-arg ref="connectionFactory" />       <!-- 非pub/sub模型(发布/订阅),即队列模式 -->       <property name="pubSubDomain"value="false" />    </bean>    <!-- 定义JmsTemplate的Topic类型 -->    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">       <constructor-arg ref="connectionFactory"/>       <!-- pub/sub模型(发布/订阅) -->       <property name="pubSubDomain"value="true" />    </bean>    <!-- ====Producer side end==== -->    <!-- ====Consumer side start==== -->    <!-- 定义Queue监听器 -->    <jms:listener-container destination-type="queue"       container-type="default" connection-factory="connectionFactory"       acknowledge="auto">       <jms:listener destination="test.queue"ref="queueReceiver" />       <jms:listener destination="test.queue"ref="queueReceiver2" />    </jms:listener-container>    <!-- 定义Topic监听器 -->    <jms:listener-container destination-type="topic"       container-type="default" connection-factory="connectionFactory"       acknowledge="auto">       <jms:listener destination="test.topic"ref="topicReceiver" />       <jms:listener destination="test.topic"ref="topicReceiver2" />    </jms:listener-container>    <!-- ====Consumer side end==== --></beans>4)      定义消息发布者(生产者)a.      Queue队列消息发布者
package com.lm.core.service.impl.sender; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.Session; importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.jms.core.JmsTemplate;importorg.springframework.jms.core.MessageCreator;importorg.springframework.stereotype.Component; @Componentpublicclass QueueSender {    @Autowired    @Qualifier("jmsQueueTemplate")    private JmsTemplate jmsTemplate;// 通过@Qualifier修饰符来注入对应的bean     /**     * 发送一条消息到指定的队列(目标)     *     *@param queueName     *           队列名称     *@param message     *           消息内容     */    public void send(String queueName, finalString message) {             jmsTemplate.send(queueName, newMessageCreator() {                       @Override                       public MessagecreateMessage(Session session) throws JMSException {                                returnsession.createTextMessage(message);                       }             });    }}b.      Topic队列信息发布者packagecom.lm.core.service.impl.sender; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.Session; importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.jms.core.JmsTemplate;importorg.springframework.jms.core.MessageCreator;importorg.springframework.stereotype.Component; @Componentpublicclass TopicSender {    @Autowired    @Qualifier("jmsTopicTemplate")    private JmsTemplate jmsTemplate;     /**     * 发送一条消息到指定的队列(目标)     *     *@param queueName     *           队列名称     *@param message     *           消息内容     */    public void send(String topicName, finalString message) {             jmsTemplate.send(topicName, newMessageCreator() {                       @Override                       public MessagecreateMessage(Session session) throws JMSException {                                returnsession.createTextMessage(message);                       }             });    }}

5)      定义消息订阅者(消费者)a)        Queue队列消息接受者1packagecom.lm.core.service.impl.receiver; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.MessageListener;importjavax.jms.TextMessage; importorg.springframework.stereotype.Component; @Componentpublicclass QueueReceiver implements MessageListener {         @Override         public void onMessage(Message message){                   try {                            System.out.println("QueueReceiver1接收到消息:"                                               +((TextMessage) message).getText());                   } catch (JMSException e) {                            e.printStackTrace();                   }         }}
b)        Queue队列消息接受者2packagecom.lm.core.service.impl.receiver; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.MessageListener;importjavax.jms.TextMessage; importorg.springframework.stereotype.Component; @Componentpublicclass QueueReceiver2 implements MessageListener {         @Override         public void onMessage(Message message){                   try {                            System.out.println("QueueReceiver2接收到消息:"                                               +((TextMessage) message).getText());                   } catch (JMSException e) {                            e.printStackTrace();                   }         }}c)        Topic队列消息接受者1packagecom.lm.core.service.impl.receiver; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.MessageListener;importjavax.jms.TextMessage; importorg.springframework.stereotype.Component; @Componentpublic classTopicReceiver implements MessageListener {         @Override         public void onMessage(Message message){                   try {                            System.out.println("TopicReceiver1接收到消息:"                                               +((TextMessage) message).getText());                   } catch (JMSException e) {                            e.printStackTrace();                   }         }}d)        Topic队列消息接受者2packagecom.lm.core.service.impl.receiver; importjavax.jms.JMSException;importjavax.jms.Message;importjavax.jms.MessageListener;importjavax.jms.TextMessage; importorg.springframework.stereotype.Component; @Componentpublicclass TopicReceiver2 implements MessageListener {         @Override         public void onMessage(Message message){                   try {                            System.out.println("TopicReceiver2接收到消息:"                                               +((TextMessage) message).getText());                   } catch (JMSException e) {                            e.printStackTrace();                   }         }}
6)      Spring mvc配置注意:需要通过mvc:resources配置静态资源,否则找不到相关依赖的资源
<?xml version="1.0"encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:mvc="http://www.springframework.org/schema/mvc"    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/mvc                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    <description>spring-mvc config</description>     <!-- 启动mvc注解 -->    <mvc:annotation-driven />     <!-- 控制器注解@Controller包自动扫描注入 -->    <context:component-scan base-package="com.lm.web" />     <!-- jackson json配置 -->    <bean id="mappingJacksonHttpMessageConverter"       class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">       <property name="supportedMediaTypes">           <list>              <value>text/html;charset=UTF-8</value>           </list>       </property>    </bean>    <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->    <bean       class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">       <property name="messageConverters">           <list>              <ref bean="mappingJacksonHttpMessageConverter"/> <!-- JSON转换器 -->           </list>       </property>    </bean>    <!-- 静态资源加载 -->    <mvc:resources location="/resources/" mapping="/resources/**" />    <!-- 定义跳转的文件的前后缀,视图模式配置 -->    <bean       class="org.springframework.web.servlet.view.InternalResourceViewResolver">       <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个可用的url地址 -->       <property name="prefix"value="/WEB-INF/view/" />       <property name="suffix"value=".jsp" />    </bean>     <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->    <bean id="multipartResolver"       class="org.springframework.web.multipart.commons.CommonsMultipartResolver">       <!-- 默认编码 -->       <property name="defaultEncoding"value="utf-8" />       <!-- 文件大小最大值 -->       <property name="maxUploadSize"value="10485760000" />       <!-- 内存中的最大值 -->       <property name="maxInMemorySize"value="40960" />    </bean></beans>
7)      实例测试a)      Queue响应信息从日志可以看出,Queue模式是单点响应消息



b)      Topic响应信息从日志可以看出,topic模式时,不管你有多少订阅者,同时响应消息




0 个回复

您需要登录后才可以回帖 登录 | 加入黑马