在實際的項目中如果使用原生的ActiveMQ API開發會比較麻煩,因為需要創建連接工廠,創建連接等,我們應該使用一個模板來做這些繁瑣的事情,Spring幫我們做了!
Spring提供了對JMS的支持,需要添加Spring支持jms的包,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.9.0</version>
</dependency>
在spring-amq.xml中配置JmsTemplate(這樣的配置沒啥問題,在實際的項目中就是這樣配置的)
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <context:component-scan base-package="com.winner.spring"/> <bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL"> <value>tcp://192.168.0.129:61616</value> </property> </bean> </property> <property name="maxConnections" value="100"></property> </bean> <!--使用緩存可以提升效率--> <bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="jmsFactory"/> <property name="sessionCacheSize" value="1"/> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="cachingConnectionFactory"/> <property name="messageConverter"> <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/> </property> </bean> <!--測試Queue,隊列的名字是spring-queue--> <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue"> <!--<constructor-arg index="0" value="spring-queue"/>--> <constructor-arg name="name" value="spring-queue"/> </bean> <!--測試Topic--> <bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic"> <constructor-arg index="0" value="spring-topic"/> </bean> </beans>
生產者
@Service public class AMQSenderServiceImpl implements AmqSenderService { private static final Logger logger = LoggerFactory.getLogger(AMQSenderServiceImpl.class); @Resource(name = "jmsTemplate") private JmsTemplate jmsTemplate; //目的地隊列的明證,我們要向這個隊列發送消息 @Resource(name = "destinationQueue") private Destination destination; //向特定的隊列發送消息 @Override public void sendMsg(MqParamDto mqParamDto) { final String msg = JSON.toJSONString(mqParamDto); try { logger.info("將要向隊列{}發送的消息msg:{}", destination, msg); jmsTemplate.send(destination, new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { return session.createTextMessage(msg); } }); } catch (Exception ex) { logger.error("向隊列{}發送消息失敗,消息為:{}", destination, msg); } } }
運行結果:
如果是Topic的話就換一下,下面的spring-topic是主題的名字。
<bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="spring-topic" />
</bean>
其他不用改!
如果想要在Spring中配置消費者的話,就不需要再啟動接收的客戶端了,這樣在測試的時候可以不需要寫消費者的代碼,因為我們要么是生產者要么是消費者!
可以通過配置一個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" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop"> <property name="connectionFactory"> <bean class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL"> <value>tcp://192.168.0.129:61616</value> </property> </bean> </property> <property name="maxConnections" value="100"></property> </bean> <!--使用緩存可以提升效率--> <bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="jmsFactory"/> <property name="sessionCacheSize" value="1"/> </bean> <!--測試Queue,隊列的名字是spring-queue--> <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="spring-queue"/> </bean> <!--測試Topic--> <bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic"> <constructor-arg index="0" value="spring-topic"/> </bean> <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="cachingConnectionFactory"/> <property name="destination" ref="destinationQueue"/> <property name="messageListener" ref="messageListener"/> </bean> <!--消息監聽器--> <bean id="messageListener" class="com.winner.spring.MyMessageListener"> </bean> </beans>
監聽器:
public class MyMessageListener implements MessageListener { @Override public void onMessage(Message msg) { if (msg instanceof TextMessage) { try { TextMessage txtMsg = (TextMessage) msg; String message = txtMsg.getText(); //實際項目中拿到String類型的message(通常是JSON字符串)之后, //會進行反序列化成對象,做進一步的處理
System.out.println("receive txt msg===" + message); } catch (JMSException e) { throw new RuntimeException(e); } } else { throw new IllegalArgumentException("Message must be of type TextMessage"); } } }
不需要寫消費者的代碼就可以知道消息有沒有推送成功
ActiveMQ結合Spring開發最佳實踐和建議:
1:Camel框架支持大量的企業集成模式,可以大大簡化集成組件間的大量服務和復雜的消息流。而Spring框架更注重簡單性,僅僅支持基本的最佳實踐。
2:Spring消息發送的核心架構是JmsTemplate,隔離了像打開、關閉Session和Producer的繁瑣操作,因此應用開發人員僅僅需要關注實際的業務邏輯。但是
JmsTemplate損害了ActiveMQ的PooledConnectionFactory對session和消息producer的緩存機制而帶來的性能提升。
3:新的Spring里面,可以設置org.springframework.jms.connection.CachingConnectionFactory的sessionCacheSize,或者干脆使用ActiveMQ的PooledConnectionFactory
4:不建議使用JmsTemplate的receive()調用,因為在JmsTemplate上的所有調用都是同步的,這意味着調用線程需要被阻塞,直到方法返回,這對性能影響很大
5:請使用DefaultMessageListenerContainer,它允許異步接收消息並緩存session和消息consumer,而且還可以根據消息數量動態的增加或縮減監聽器的數量