ActiveMQ與Spring整合:(1)基本使用

        最近在學習Java消息服務(JMS),Java消息服務主要是用在應用間解耦。比如,我們經常用到的短信服務,一筆交易完成之後,我們可能需要發送短信,爲了加快系統響應速度,我們可能需要把短信設計成異步的,我們只需要把短信發送給短信平臺,最終短信是否成功交由短信平臺來處理。另外一種使用場景就是支付交易,一筆支付交易完成之後,支付平臺需要後臺異步通知商戶,支付已經成功。這個通知通常也會做成異步的。像以上兩種使用場景,我們就可以使用Java消息服務來實現。

Java消息服務(JMS),只是一組規範,即API。它的具體實現由廠商自己去實現,就像JDBC一樣。目前使用較多的實現有ActiveMQ,RabbitMQ,kafuka。接下來主要介紹ActiveMQ的一些基本概念以及與Spring的整合。

        JMS分爲兩種消息傳送模式,點到點模式(P2P),發佈訂閱模式(Pub/Sub)模式。點到點模式組成包括:消息發送者,接受者,JMS提供者(broken服務器);P2P消息目的地稱爲隊列Queue,且消息只能被一個接受者接受。發佈訂閱模式組成包括:發佈者,訂閱者,JMS提供者(broken服務器),發佈訂閱的目的地稱爲主題Topic,且消息能夠被多個訂閱者接受。

        接下來主要是介紹Spring與ActiveMQ的結合使用,主要介紹P2P消息隊列。把消息發送者,消息接收者放在兩個應用,使用外部ActiveMQ。

1、新建JMS消息發送者應用,ActiveMQ_Producer。applicationContext.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    
	<!-- 連接池  -->
    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">  
        <property name="connectionFactory">  
            <!-- 連接工廠 -->
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">  
                <property name="brokerURL" value="tcp://localhost:61616" />  
            </bean>  
        </property>
         <property name="maxConnections" value="10"/>   
    </bean> 
    
    <!-- 消息模板 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">  
        <property name="connectionFactory" ref="pooledConnectionFactory" />  
        <property name="defaultDestination" ref="queueDestination" />  
        <property name="messageConverter">  
            <bean class="org.springframework.jms.support.converter.SimpleMessageConverter" />
       </property>
         <!-- 消息轉換器 -->  
<!--     	<property name="messageConverter" ref="emailMessageConverter"/> -->
    </bean>
    
      <!-- 配置消息目標 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">  
        <!-- 目標,在ActiveMQ管理員控制檯創建 http://localhost:8161/admin/queues.jsp -->
        <constructor-arg index="0" value="helloQueue" />  
    </bean> 
    <!-- 用於測試消息回覆的 -->  
	<bean id="responseQueue" class="org.apache.activemq.command.ActiveMQQueue">  
	    <constructor-arg>  
	        <value>responseQueue</value>  
	    </constructor-arg>  
	</bean>
    
      <!-- 消息監聽器 -->  
    <bean id="responseMessageListener" class="com.hua.spring.jms.listener.ResponseQueueMessageListener"/>  
    
     <!-- 消息監聽容器 -->   
    <bean id="responseQueueListenerAdapter" class=" org.springframework.jms.listener.DefaultMessageListenerContainer">  
          <property name="connectionFactory" ref="pooledConnectionFactory" />  
        <property name="destination" ref="responseQueue" />  
        <property name="messageListener" ref="responseMessageListener" /> 
         <property name="sessionTransacted" value="false"/> 
    </bean>
  
 
    
    
</beans>
主要有兩個隊列,一個是發送隊列queueDestination,一個是用來接收響應的隊列responseQueue。採用異步接受消息,所以接收響應的隊列responseQueue需要配置監聽器,並把監聽器放入監聽容器。監聽器需要實現MessageListener接口,或者SessionAwareMessageListener接口。

2、新建監聽器類:ResponseQueueMessageListener.java

package com.hua.spring.jms.listener;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @description
 * @date:(2016-8-25 下午10:01:07)
 * @author Administrator
 * @version v1.0
 * @since v1.0
 *
 * Modified history
 *
 *    Modified date:  
 *    Modifier user:     
 *    description: 
 *
 * */
public class ResponseQueueMessageListener implements MessageListener{
	
	private Logger logger=LoggerFactory.getLogger(ResponseQueueMessageListener.class);

	@Override
	public void onMessage(Message message) {
		if(message instanceof TextMessage){
			try {
				String text=((TextMessage) message).getText();
				logger.info("消息生產者接收到響應:"+text);
			} catch (JMSException e) {
				logger.error("消息生產者接收消息時發生異常:",e);
				
			}
			
		}
		
	}

}
監聽器類實現了MessageListener接口,這個接口只有一個方法public void onMessage(Message message)。

3、新建消息提供者啓動類Main.java

package com.jms.producer.client;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;


/**
 * @description
 * @date:(2016-8-28 上午9:43:03)
 * @author Administrator
 * @version v1.0
 * @since v1.0
 *
 * Modified history
 *
 *    Modified date:  
 *    Modifier user:     
 *    description: 
 *
 * */
public class Main {
	
	private static Logger logger=LoggerFactory.getLogger(Main.class);
	
	public static void main(String[] args) {
		
		
		
		ApplicationContext context=new ClassPathXmlApplicationContext(
				"/config/applicationContext.xml");
		JmsTemplate jmsTemplate=(JmsTemplate)context.getBean("jmsTemplate");
		jmsTemplate.send("helloQueue", new MessageCreator() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				String msg="發送者:我是消息生產者";
				TextMessage textMessage=session.createTextMessage(msg);
				logger.info(msg);
				return textMessage;
			}
		});
	}

}
4、另外日誌輸出配置文件logback.xml如下:

<configuration>   
   
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">   
    <!-- encoder 默認配置爲PatternLayoutEncoder -->   
    <encoder>   
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>   
    </encoder>   
  </appender>   
   
  <root level="info">             
    <appender-ref ref="CONSOLE" />   
  </root>     
     
 </configuration> 
項目目錄結構如下:



5、新建消息接受者應用ActiveMQ_Consumer,applicationContext.xml如下:

<pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    
	<!-- 連接池  -->
    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">  
        <property name="connectionFactory">  
            <!-- 連接工廠 -->
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">  
                <property name="brokerURL" value="tcp://localhost:61616" />  
            </bean>  
        </property>
         <property name="maxConnections" value="10"/>   
    </bean> 
    
    <!-- 消息模板 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">  
        <property name="connectionFactory" ref="pooledConnectionFactory" />  
        <property name="defaultDestination" ref="queueDestination" />  
        <property name="messageConverter">  
            <bean class="org.springframework.jms.support.converter.SimpleMessageConverter" />
       </property>
         <!-- 消息轉換器 -->  
<!--     	<property name="messageConverter" ref="emailMessageConverter"/> -->
    </bean>
    
      <!-- 配置消息目標 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">  
        <!-- 目標,在ActiveMQ管理員控制檯創建 http://localhost:8161/admin/queues.jsp -->
        <constructor-arg index="0" value="helloQueue" />  
    </bean> 
    <!-- 用於測試消息回覆的 -->  
	<bean id="responseQueue" class="org.apache.activemq.command.ActiveMQQueue">  
	    <constructor-arg>  
	        <value>responseQueue</value>  
	    </constructor-arg>  
	</bean>
	
	    <!-- 可以獲取session的MessageListener -->  
    <bean id="queueDestinationMessageListener" class="com.hua.spring.jms.listener.QueueDestinationMessageListener">  
        <property name="destination" ref="responseQueue"/>
    </bean> 
    
     <!-- 消息監聽容器 -->   
    <bean id="responseQueueListenerAdapter" class=" org.springframework.jms.listener.DefaultMessageListenerContainer">  
          <property name="connectionFactory" ref="pooledConnectionFactory" />  
        <property name="destination" ref="queueDestination" />  
        <property name="messageListener" ref="queueDestinationMessageListener" /> 
         <property name="sessionTransacted" value="false"/> 
    </bean>

</beans>



消息接受者配置也是兩個隊列,其中要對消息發送者隊列queueDestination進行監聽,配置監聽器並把監聽器註冊到監聽容器。

6、新建監聽器類QueueDestinationMessageListener.java。實現SessionAwareMessageListener接口,這樣就可以對消息進行相應響應,不需要進行響應時可實現MessageListener接口。則不能進行

package com.hua.spring.jms.listener;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.listener.SessionAwareMessageListener;

/**
 * @description
 * @date:(2016-8-28 上午9:49:32)
 * @author Administrator
 * @version v1.0
 * @since v1.0
 *
 * Modified history
 *
 *    Modified date:  
 *    Modifier user:     
 *    description: 
 *
 * */
public class QueueDestinationMessageListener implements SessionAwareMessageListener<Message>{
	
	private Logger logger=LoggerFactory.getLogger(QueueDestinationMessageListener.class);
	
	private Destination destination;

	@Override
	public void onMessage(Message message, Session session) throws JMSException {
		if(message instanceof TextMessage){
			try {
				String text=((TextMessage)message).getText();
				logger.info("接受者:我收到消息-->"+text);
				
				MessageProducer producer = session.createProducer(destination);  
		        Message textMessage = session.createTextMessage("我是消息接收者,我已接收到消息");  
		        producer.send(textMessage);
				
			} catch (JMSException e) {
				logger.error("監聽消息發生異常",e);
		
			}
			
		}
		
	}

	public Destination getDestination() {
		return destination;
	}

	public void setDestination(Destination destination) {
		this.destination = destination;
	}

}
7、新建消息接受者應用的啓動類:

package com.jms.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @description
 * @date:(2016-8-28 上午10:27:43)
 * @author Administrator
 * @version v1.0
 * @since v1.0
 *
 * Modified history
 *
 *    Modified date:  
 *    Modifier user:     
 *    description: 
 *
 * */
public class Consumer {
	
	public static void main(String[] args) {
		
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext(
				"/config/applicationContext.xml");
	}

}
整體項目結構如下:



下載ActiveMQ,我用到的是apache-activemq-5.8.0,解壓後如下。


進入到lib目錄,如果是window環境,就點擊activemq.bat;Linux環境就執行activemq這樣就可以啓動broken服務器了。

執行Main.java和Consumer.java可以看到如下日誌:

ActiveMQ_Producer的日誌:


ActiveMQ_Consumer的日誌:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章