ActiveMQ学习笔记(五)—— 与Spring整合

Spring整合ActiveMQ

maven引入依赖

<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>4.3.23.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-pool</artifactId>
			<version>5.15.9</version>
		</dependency>

发送队列消息

<?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:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <context:component-scan base-package="cn.fg.jsm.producer" />
    
    <!-- activemq 连接池 -->
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
    	<property name="connectionFactory">
    		<bean class="org.apache.activemq.ActiveMQConnectionFactory">
        		<property name="brokerURL" value="tcp://192.168.1.3:61616" /> <!-- activemq 服务器地址 -->
    		</bean>
    	</property>
    	<!-- <property name="maxConnections" value="10" /> -->  <!-- 最大连接数,默认1 -->
    	<!-- <property name="maximumActiveSessionPerConnection" value="100" /> --> <!-- 每个连接的最大会话数,默认500 -->
    	<!-- <property name="idleTimeout" value="60000" /> --> <!-- 创建的连接的空闲超时值(毫秒),默认30秒 -->
    </bean>
    
    <!-- 创建 queue -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue03"/>
    </bean>
    
    <!-- 创建 topic -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic03"/>
    </bean>
    
    <!-- 创建jmsTemplate -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="queueDestination"/> <!-- 默认目的地,队列或主题 -->
        <!-- spring 消息转换器,可以使用convertAndSend发送或接收消息,默认为SimpleMessageConverter,存在多个转换器,使用搜百度 -->
        <property name="messageConverter">  
        	<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"></bean>
        </property>
    </bean>
    
    <!-- 配置jms事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
		<property name="connectionFactory" ref="connectionFactory"/>
	</bean>
	
	<!-- 注解方式配置事物 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
	
</beans>
package cn.fg.jsm.producer;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

@Component
public class ProducerQueue {
    
    @Autowired
    @Qualifier("jmsTemplate4Queue03") //当有多个jmsTemplate时,指定使用哪一个
    private JmsTemplate jmsTemplate;  //这个jmsTemplate有一个默认目的地Queue03
    
    //发送消息
    public static void main(String[] args) {
    	ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
    	ProducerQueue producerQueue = ctx.getBean(ProducerQueue.class);
    	
    	//使用消息转换器发送消息
    	producerQueue.jmsTemplate.convertAndSend("这是一个convertAndSend消息:" + System.currentTimeMillis());
    	
    	//可以发送给其他目的地,convertAndSend有很多重载方法
    	producerQueue.jmsTemplate.convertAndSend("queue01", "这是一个queue01消息:" + System.currentTimeMillis());
    	
    	//使用session发送消息
    	producerQueue.jmsTemplate.send(new MessageCreator() {
			@Override
			public Message createMessage(Session session) throws JMSException {
				//原生写法创建一个TextMessage
				TextMessage textMessage = session.createTextMessage("这是一个TextMessage消息:" + System.currentTimeMillis());
				return textMessage;
			}
		});
    	
    	System.out.println("消息发送完毕");
	}
}
package cn.fg.jsm.producer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class ProducerQueue {
    
    @Autowired
    private JmsTemplate jmsTemplate;
    
    @Transactional()  //开启事务
    public void send(){

        
        //使用spring转换器发送消息
        jmsTemplate.convertAndSend("这是一个convertAndSend消息:" + System.currentTimeMillis());
        
        //测试异常,异常后事务回滚,消息不会发送到mq服务器
		//int i = 1 / 0;

        //使用普通发送消息
        /*jmsTemplate.send(new MessageCreator() { 
            @Override
            public Message createMessage(Session session) throws JMSException {
                TextMessage textMessage = session.createTextMessage(String.valueOf(System.currentTimeMillis()));
                return textMessage;
            }
        });*/
        
        System.out.println("消息发送完毕");
    }
    
    public static void main(String[] args) {
    	ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
        ProducerQueue producer = ctx.getBean(ProducerQueue.class);
        producer.send(); //调用生产者发送消息
	}
}

接收队列消息

这里我们使用监听容器接收消息

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <context:component-scan base-package="cn.fg.consumer" />
    
    <!-- activemq 连接池 -->
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
    	<property name="connectionFactory">
    		<bean class="org.apache.activemq.ActiveMQConnectionFactory">
        		<property name="brokerURL" value="tcp://192.168.1.3:61616" /> <!-- activemq 服务器地址 -->
    		</bean>
    	</property>
    	<!-- <property name="maxConnections" value="10" /> -->  <!-- 最大连接数,默认1 -->
    	<!-- <property name="maximumActiveSessionPerConnection" value="100" /> --> <!-- 每个连接的最大会话数,默认500 -->
    	<!-- <property name="idleTimeout" value="60000" /> --> <!-- 创建的连接的空闲超时值(毫秒),默认30秒 -->
    </bean>
    
    <!-- 接收消息的 queue -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue03"/>
    </bean>
    
    <!-- 接收消息的 topic -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic03"/>
    </bean>

	<!-- 消息监听容器 -->
	<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="queueDestination" /> <!-- 监听的目的地,队列或主题 -->
		<!-- 指定具体的监听器,spring提供的监听器实现类有多个 -->
		<!-- queueMessageListener是我自己定义的实现类 -->
		<!-- QueueMessageListener类已经加了@Component注解,所以这里可以不用单独定义一个bean了 -->
		<property name="messageListener" ref="queueMessageListener" /> 
	</bean>
	
</beans>
package cn.fg.consumer;

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

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

//监听器,这里我们用来监听queue03
@Component
public class QueueMessageListener implements MessageListener {

	@Override
	public void onMessage(Message message) {
		if(message != null && message instanceof TextMessage){
			TextMessage textMessage = (TextMessage) message;
			try {
				System.out.println(textMessage.getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
		
	}
	
    //启动消费者
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("spring-jms.xml");
	}

}

发送主题消息

<!-- 创建 topic -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic03"/>
    </bean>
    
    <!-- 创建jmsTemplate -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="topicDestination"/> <!-- 改为主题 -->
        <!-- messageConverter 默认值就是SimpleMessageConverter 可以不用写 -->
        <!-- <property name="messageConverter">  
        	<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"></bean>
        </property> -->
    </bean>
package cn.fg.jsm.producer;

import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class ProducerTopic {
    
    @Autowired
    private JmsTemplate jmsTemplate;
    
    @Autowired
    private ActiveMQTopic activeMQTopic; //使用xml中定义的主题
    
    @Transactional()  
    public void send(){
    	
    	//发送主题
    	jmsTemplate.convertAndSend(activeMQTopic, "topic03:"+ System.currentTimeMillis());
    	
    	//也可以不用再xml定义 new一个主题发送
        //jmsTemplate.convertAndSend(new ActiveMQTopic("topic04"), "topic04:"+ System.currentTimeMillis());
        
        System.out.println("消息发送完毕");
    }
    
    public static void main(String[] args) {
    	ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-jms.xml");
        ProducerTopic producer = ctx.getBean(ProducerTopic.class);
        producer.send(); //调用生产者发送消息
	}
}

接收主题消息

<!-- 接收消息的 queue -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue03"/>
    </bean>
    
	<!-- 队列消息监听容器 -->
	<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="queueDestination" /> <!-- 监听的目的地,队列或主题 -->
		<!-- 指定具体的监听器,spring提供的监听器实现类有多个 -->
		<!-- queueMessageListener是我自己定义的实现类 -->
		<!-- QueueMessageListener类已经加了@Component注解,所以这里可以不用单独定义一个bean了 -->
		<property name="messageListener" ref="queueMessageListener" /> 
	</bean>
	
	
	<!-- 接收消息的 topic -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic03"/>
    </bean>
	
	<!-- 可以在定义一个监听主题的监听器 -->
	<bean id="topicMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="topicDestination" /> <!-- 设置需要监听的主题 -->
		<property name="messageListener" ref="topicMessageListener" /> 
	</bean>
package cn.fg.consumer;

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

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

//监听器,这里我们用来监听topic03
@Component
public class TopicMessageListener implements MessageListener {

	@Override
	public void onMessage(Message message) {
		if(message != null && message instanceof TextMessage){
			TextMessage textMessage = (TextMessage) message;
			try {
				System.out.println(textMessage.getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("spring-jms.xml");
	}

}

持久主题订阅

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <context:component-scan base-package="cn.fg.consumer" />
    
    <!-- 连接池 -->
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
    	<property name="connectionFactory">
    		<bean class="org.apache.activemq.ActiveMQConnectionFactory">
        		<property name="brokerURL" value="tcp://192.168.1.3:61616" />
    			<property name="clientID" value="004" /> <!-- 设置clientID,持久主题订阅必须的 -->
    		</bean>
    	</property>
    </bean>
	
	<!--  topic -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic04"/>
    </bean>
	
	<!-- 监听容器 -->
	<bean id="topicMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="topicDestination" /> <!-- 设置需要监听的主题 -->
		<property name="messageListener" ref="durableTopicMessageListener" />  <!-- 监听实现类 -->
		<!-- <property name="subscriptionDurable" value="true"/>   --> <!-- 开启持久订阅,默认false -->
		<!-- 设置持久订阅名称,如果名称不为null,则subscriptionDurable自动设置为true -->
		<property name="durableSubscriptionName" value="mydurableSubscription" /> 
	</bean>
</beans>
package cn.fg.consumer;

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

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

//监听实现类
@Component
public class DurableTopicMessageListener implements MessageListener {

	@Override
	public void onMessage(Message message) {
		if(message != null && message instanceof TextMessage){
			TextMessage textMessage = (TextMessage) message;
			try {
				System.out.println(textMessage.getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	//启动消费者
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("spring-durable-topic.xml");
	}

}

消息监听适配器MessageListenerAdapter

MessageListenerAdapter在监听到消息的同时,还可以使用当前的session回复消息

TextMessage textMessage = session.createTextMessage("这是一个消息" + System.currentTimeMillis());
textMessage.setJMSReplyTo(new ActiveMQQueue("queue-replyto")); //生产者发送消息时设置了回复地址(队列)
messageProducer.send(textMessage);
package cn.fg.consumer;

import org.springframework.stereotype.Component;

//自定义的消费者监听类,不实现任何接口
@Component
public class ConsumerListener {
    
    /**
     * 用来接收消息的方法,参数为生产者发送的消息内容
     * MessageListenerAdapter会把接收到的消息做如下转换:
     * TextMessage转换为String
     * BytesMessage转换为byte[]
     * MapMessage转换为Map
     * ObjectMessage转换为对应的Serializable
     */
    public void handleMessage(String message) {
        System.out.println("handleMessage:" + message);
    }
    
    /**
     * 如果方法有返回值,则会以该返回值作为消息内容进行回复
     * 返回值类型同样遵循上述转换规则
     * @return
     */
    public String receiveMessage(String message) {
        System.out.println("receiveMessage:" + message);
        return "bbbbbbbbbbbbbbbbb";
    }

}
<!-- 接收消息的 queue -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="queue03"/>
</bean>

<!-- 消息监听适配器 -->
<bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
	<property name="delegate" ref="consumerListener" /> <!-- 监听委托类,需要自己创建,consumerListener已经@Component -->
	<property name="defaultListenerMethod" value="receiveMessage"/> <!-- 监听方法名,需要在委托类中创建该方法,默认为 handleMessage-->
	
	<!-- 默认回复目的地,如果生产者未设置JMSReplyTo,则以该值作为回复地址 -->
   	<!-- <property name="defaultResponseDestination" ref="responseDestination"/> --> 
</bean>

<!-- 消息监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory" />
	<property name="destination" ref="queueDestination" /> <!-- 监听哪个队列 -->
	<property name="messageListener" ref="messageListenerAdapter" /> <!-- 监听器,这里我们注入messageListenerAdapter -->
</bean>

执行情况:调用生产者发送消息,消费者监听到消息后,同时又向queue-replyto回复了消息

发布了64 篇原创文章 · 获赞 0 · 访问量 3211

猜你喜欢

转载自blog.csdn.net/q42368773/article/details/103151871