ActiveMQ——7.Spring-jms的配置

来源:互联网 发布:君何以知燕王句式 编辑:程序博客网 时间:2024/06/07 01:13

概述


如何使用spring-jms来简化jms客户端的开发?
这篇文章主要记录如何配置以便以后复用。

producer端


producer端负责发送,这里使用JmsTemplate。

spring配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">            <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://localhost:61616" />    </bean>        <!-- create template for send message -->    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">        <!-- bind the connection factory -->        <property name="connectionFactory" ref="connectionFactory" />        <property name="defaultDestinationName" value="jms-config" />    </bean></beans>

JmsTemplate默认将jms-config解析为Queue类型的Destination。如果需要将其解析为Topic类型,需要为jmsTemplate指定属性pubSubDomain=true,配置如下:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">    <!-- bind the connection factory -->    <property name="connectionFactory" ref="connectionFactory" />    <property name="pubSubDomain" value="true" />    <property name="defaultDestinationName" value="jms-config" /></bean>

测试类
package cn.sinobest.asj.producer.springsupport.jt;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.jms.core.JmsTemplate;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) // 配置spring组件运行时@ContextConfiguration(locations="classpath:spring-jms-demo.xml") // 配置文件public class JmsTemplateSendWithContextTest {    @Resource(name = "jmsTemplate")    private JmsTemplate jt;        @Test    public void testSendToDefaultDestination() {        String message = "you can config JmsTemplate in xml, then use it for send.";        jt.convertAndSend(message);    }}
展示这个测试类,是想告诉大家使用Spring+JUnit4的注解编写单元测试,可以非常方便的加载Spring配置并初始化bean资源;使用Resource注解可以获取bean资源。

consumer端


consumer端负责接收,接收有同步、异步两种方式

同步接收

这里使用JmsTemplate进行同步接收。上面已经给过了使用JmsTemplate发送的配置,接收和发送的配置能有什么区别呢?
如果我们不希望客户端一直阻塞等待消息,那么需要关心receiveTimeout属性,单位毫秒。如果超过了这个时间,还没有接收到消息,就返回null。
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">    <!-- bind the connection factory -->    <property name="connectionFactory" ref="connectionFactory" />    <property name="defaultDestinationName" value="jms-config" />    <property name="receiveTimeout" value="3000" /></bean>

异步接收

异步接收是基于监听器的接收,传统的配置方式是配置一个ListenerContainer的bean,在这个bean里维护listener。还有一种精简的配置方案,可以在一个container中放置多个listener。

传统的配置

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">            <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://localhost:61616" />    </bean>        <bean id="messageListener" class="cn.sinobest.asj.consumer.springsupport.async.SimpleMessageListener" />    <bean id="messageContainer"        class="org.springframework.jms.listener.DefaultMessageListenerContainer">        <property name="connectionFactory" ref="connectionFactory" />        <property name="destinationName" value="jms-config" />        <property name="messageListener" ref="messageListener" />    </bean></beans>

其中,SimpleMessageListener是接口javax.jms.MessageListener的实现类。

DefaultMessageListenerContainer负责将messageListener注册到connectionFactory的destination,一旦destination中有消息,就会将消息推送给messageListener。
DefaultMessageListenerContainer有很多特性的配置,下面择要介绍:

1.Destination及类型

使用下面的API,可以设置Destination
  • public void setPubSubDomain(boolean pubSubDomain)
    设置destination的类型,true-Topics,false-Queues;默认为false。
  • public void setDestinationName(String destinationName)
    设置destination的name,结合pubSubDomain使用,根据destinationName解析为具体的Destination。
  • public void setDestination(Destination destination)
    设置destination。

2.多线程

一个DMLC的实例,只能管理一个MessageListener实例,但是可以使用下面的方法设置多线程:
  • public void setConcurrency(String concurrency)
    通过"lower-upper"格式的字符串,设置线程数的下限和上限,如"5-10";或者仅设置上限,下限默认为1,如"10"。
如果没有使用事务,多线程可以显著提高监听器的接收速度。

3.确认模式

下面的API用来设置确认模式:
  • public void setSessionAcknowledgeMode(int sessionAcknowledgeMode)
    设置确认模式,sessionAcknowledgeMode可以取javax.jms.Session.AUTO_ACKNOWLEDGE(默认),javax.jms.Session.CLIENT_ACKNOWLEDGE,javax.jms.Session.DUPS_OK_ACKNOWLEDGE。
  • public void setSessionAcknowledgeModeName(String constantName)
    通过名字来设置确认模式,默认为"AUTO_ACKNOWLEDGE"。

4.事务

下面的API,用来设置事务:
  • public void setSessionTransacted(boolean sessionTransacted)
    设置是否使用事务,默认为false。
 
更多DefaultMessageListenerContainer的相关配置,参考其API。

精简的配置

称之为精简版的配置,因为一个容器可以配置多个监听器。
<?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:amq="http://activemq.apache.org/schema/core"       xmlns:jms="http://www.springframework.org/schema/jms"       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-4.1.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context-4.1.xsd        http://www.springframework.org/schema/mvc        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd        http://www.springframework.org/schema/jms        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd        http://activemq.apache.org/schema/core        http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd">            <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://localhost:61616" />    </bean>    <!-- 定义Topic监听器 -->        <jms:listener-container destination-type="topic" container-type="default" connection-factory="connectionFactory" acknowledge="auto">          <!-- 这里的Destination是自定义的,ref对应的是创建的messagelistener类名小写 -->        <jms:listener destination="test.topic" ref="topicReceiver1"/>            <jms:listener destination="test.topic" ref="topicReceiver2"/>        </jms:listener-container>     </beans>
注意:精简版的schema和传统版不一样,详细的精简版可以参考Spring整个ActiveMQ(精简版配置)
listener-container作为容器,可以有多个listener子元素,每个listener代表一个监听器。

1.Destination类型

listener-container有destination-type属性,可以取值["queue", "topic"],默认为"queue",它决定了listener将destination解析为Queue还是Topic类型。

2.pojo监听器

listener会对消息进行转换,所以ref的目标bean是一个pojo,method是这个pojo的方法的名字——这个方法的参数要和Message中的数据类型兼容。下面给出我们使用的topicReceiver1
package com.gwd.mq.producer.topic;        import javax.jms.JMSException;    import javax.jms.Message;    import javax.jms.MessageListener;    import javax.jms.TextMessage;    import org.springframework.stereotype.Component;         @Component    public class TopicReceiver1 implements MessageListener{            public void onMessage(Message message) {            try {                System.out.println("TopicReceiver1接收到消息:"+((TextMessage)message).getText());            } catch (JMSException e) {                e.printStackTrace();            }        }    }  

3.多线程

为listener-container元素设置concurrency属性,可以指定线程数的下限和上限。这一点和DefaultMessageListenerContainer的相同

4.确认模式和事务4

listener-container的acknowledge属性,可以指定确认模式或者事务,取值范围["auto", "client", "dups-ok", "transacted"];默认为"auto",事务使用"transacted"。
 
更多精简配置相关的参数,参考spring-jms-4.2.xsd

可信任的包

ObjectMessage的使用机制是不安全的,ActiveMQ自5.12.2和5.13.0之后,强制consumer端声明一份可信任的包列表,只有当ObjectMessage中的Object在可信任包内,才能被提取出来。
添加可信任的一般常用两种,一种按自己的需求添加,另一种是添加全部可信任
//按需添加信任代码版设置ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");factory.setTrustedPackages(new ArrayList(Arrays.asList("org.apache.activemq.test,org.apache.camel.test".split(","))));
//完全信任的代码版设置ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");factory.setTrustAllPackages(true);

配置版分别对应如下:
<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">    <property name="brokerURL" value="tcp://localhost:61616"/>    <property name="trustedPackages">        <list>            <value>org.apache.activemq.test</value>            <value>org.apache.camel.test</value>        </list>    </property></bean><bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">    <property name="connectionFactory" ref="connectionFactory"/></bean><bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">    <property name="configuration" ref="jmsConfig"/></bean>

<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">    <property name="brokerURL" value="tcp://localhost:61616"/>    <property name="trustAllPackages" value="true"/></bean><bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">    <property name="connectionFactory" ref="connectionFactory"/></bean><bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">    <property name="configuration" ref="jmsConfig"/></bean>
关于ObjectMessage安全性的说明,参考官方文档

ConnectionFactory的bean配置

一般有如下几种:

1.ActiveMQConnectionFactory

在前面的配置中,我们已经接触了这个配置:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"><property name="brokerURL" value="tcp://localhost:61616" /></bean>

2.SingleConnectionFactory

 
使用org.springframework.jms.connection.SingleConnectionFactory对ActiveMQConnectionFactory进行包装,建议用于测试或者单机的环境。
<bean id="connectionFactory"    class="org.springframework.jms.connection.SingleConnectionFactory">    <property name="targetConnectionFactory">        <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">            <property name="brokerURL" value="tcp://localhost:61616" />        </bean>    </property></bean>

3.PooledConnectionFactory

使用org.apache.activemq.pool.PooledConnectionFactory对ActiveMQConnectionFactory进行包装。
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">    <property name="connectionFactory">        <bean class="org.apache.activemq.ActiveMQConnectionFactory">            <property name="brokerURL" value="tcp://localhost:61616" />        </bean>    </property></bean>

方式的选择:
1.如果只需要一个connection选择ActiveMQConnectionFactory,如果需要多个connection选择PooledConnectionFactory
 2.By default the pooled version will Idle out old connections after some time of non-use. The ActiveMQ connection created from its factory is valid until you call close() or it is no longer referenced。(摘自stackoverflow,大致意思是PooledConnectionFactory会释放长连接,ActiveMQConnectionFactory不会释放直到你关闭它或者不再引用)
 3.SingleConnectionFactory一般用于测试或者单机环境







原创粉丝点击