ActiveMQ与spring整合注解方式

之前有用过activeMq这种消息中间件,但是通过配置文件的方式,现在spring都越来越推行注解,所以写一个小demo来记录一下。

1.什么是ActiveMQ

ActiveMQ是Apache出品的一款基于JMS规范的消息中间件。

2.什么是JMS

Java Message Service(JMS)是SUN提出的旨在统一各种MOM(Message-Oriented Middleware )系统接口的规范,它包含点对点(Point to Point,PTP)和发布/订阅(Publish/Subscribe,pub/sub)两种消息模型,提供可靠消息传输、事务和消息过滤等机制。简单来说,jms定制一个规范,而ActiveMQ就是这个规范的实现。(就如同 jdbc规范,和各个数据库厂商基于这个规范提供的jdbc驱动。)其中JMS定义了五种不同的消息正文格式

  • StreamMessage – Java原始值的数据流
  • MapMessage–一套名称-值对
  • TextMessage–一个字符串对象(最常用)
  • ObjectMessage–一个序列化的 Java对象
  • BytesMessage–一个字节的数据流
3.ActiveMQ的消息形式

(1) 队列(queue) :点对点消息通信(point-to-point)
消息发送者发送消息,并将发送的消息放在 一个队列当中,接收消息的一方从队列当中获取消息,消息被接收后,将移出消息队列。
在这里插入图片描述
(2)主题(topic) :发布(publish) /订阅(subscribe)消息通信
消息发的发送者发送消息到主题,多个订阅者(消息的接受者),订阅了这个主题,那么消息发布到主题时,多个订阅者都能接收到消息。
在这里插入图片描述

4.ActiveMQ的作用以及使用场景。

大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力。
(1)异步处理
比如:户注册业务,用户注册完之后,需要给用户发送注册邮件,注册 与发送邮件是同步执行的。但是注册完成的通知邮件,并不需要立即给用户发送,可以把这个消息发送给消息队列,然后发送邮寄这个功能异步读取,消息队列里面的内容,然后执行相关操作,可以提高系统的运行速度。
在这里插入图片描述

(2)应用解耦
比如:我们常见的场景,用户下一个订单之后,我们要调用库存系统,来进行相关业务,如果是在订单系统中 直接调用库存系统,那么两个系统的耦合度就会比价高,所以可以通过消息中间件来进行系统解耦。
在这里插入图片描述
(3)流量消减
比如处理秒杀系统的一种解决方案,如果每次用户的请求都直接发送给秒杀处理业务,系统将承受很大的压力,所以可以将秒杀的用户安装先后顺序,进入消息队列,设置消息队列的容量,队列满了之后,就无法获取再进队列,然后系统从消息对队列中获取消息,处理秒杀之后的相关操作。
在这里插入图片描述

5.spring整合ActiveMQ

(1)创建测试工程
在这里插入图片描述
(2)在父工程的pom.xml导入相关依赖

 <!-- 导入相关依赖 -->
  <dependencies>
  	 <dependency>
  	 	 <groupId>org.springframework</groupId>
  		 <artifactId>spring-context</artifactId>
     	 <version>4.3.12.RELEASE</version>
  	 </dependency>
  	 
  	 <!-- jsm整合规范包 -->
  	 <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-jms</artifactId>
	    <version>4.3.12.RELEASE</version>
	</dependency>
	
	<!--  activemq先关依赖-->
	<dependency>
	    <groupId>org.apache.activemq</groupId>
	    <artifactId>activemq-all</artifactId>
	    <version>5.11.2</version>
	</dependency>
	
	<dependency>
	    <groupId>log4j</groupId>
	    <artifactId>log4j</artifactId>
	    <version>1.2.17</version>
	</dependency>
  </dependencies>

相关配置文件信息conf.properties

activemq.url=tcp://192.168.25.128:61616
activemq.queueName=message-queue
activemq.topicName=message-topic

(3)配置生产者

/**
 * 
 * 配置activeMq的发送者
 * @author Hao
 * @date: 2019年6月9日 上午11:06:51 
 * @Description:
 * 参照配置版本
 * :	<!-- 配activemq -->
	<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
	<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://192.168.25.128:61616" />
	</bean>
	<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
	<bean id="connectionFactory"
		class="org.springframework.jms.connection.SingleConnectionFactory">
		<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
		<property name="targetConnectionFactory" ref="targetConnectionFactory" />
	</bean>
		<!-- 配置生产者 -->
	<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
		<property name="connectionFactory" ref="connectionFactory" />
	</bean>
	<!--这个是队列目的地,点对点的 -->
	<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg>
			<value>spring-queue</value>
		</constructor-arg>
	</bean>
	<!--这个是主题目的地,一对多的 -->
	<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg value="Itemtopic" />
	</bean>
 </beans>
 */
import org.springframework.jms.core.JmsTemplate;
@Configuration
@PropertySource("classpath:conf.properties")
public class ProducerConfig {
	
	@Value("${activemq.url}")
	String URL;
	
	@Value("${activemq.queueName}")
	String QUEUE_NAME;
	
	@Value("${activemq.topicName}")
	String TOPIC_NAME;

	@Bean
	//配置ConnectionFactory用于生成connection
	public ActiveMQConnectionFactory connectionFactory(){
		ActiveMQConnectionFactory activeMQConnectionFactory
										= new ActiveMQConnectionFactory(URL);
		return activeMQConnectionFactory;
	}
	
	@Bean
	//注册SingleConnectionFactory,这个spring的一个包装工厂 用于管理真正的ConnectionFactory
	public SingleConnectionFactory singleConnectionFactory(ActiveMQConnectionFactory activeMQconnectionFactory){
		SingleConnectionFactory connectionFactory = new SingleConnectionFactory();
		//设置目标工厂
		connectionFactory.setTargetConnectionFactory(activeMQconnectionFactory);
		return connectionFactory;
	}
	
	@Bean
	//配置生产者,jmsTemplate
	public JmsTemplate jmsTemplate(SingleConnectionFactory connectionFactory){
		JmsTemplate jmsTemplate = new JmsTemplate();
		jmsTemplate.setConnectionFactory(connectionFactory);
		return jmsTemplate;
	}
	
	/**
	 * 配置队列目的的: 根据测试需要配置其中一个
	 * 	1.队列  点对点 queue
	 *  2.主题  一对多  topic
	 * */
	
	@Bean //
	public ActiveMQQueue queueDestination(){
		ActiveMQQueue activeMQQueue = new ActiveMQQueue(QUEUE_NAME);
		return activeMQQueue;
	}
	
	@Bean
	public ActiveMQTopic topicDestination(){
		ActiveMQTopic activeMQTopic = new ActiveMQTopic(TOPIC_NAME);
		return activeMQTopic;
	}
}

(4)配置消费者

package com.kuake.config;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.connection.SingleConnectionFactory;
import org.springframework.jms.listener.DefaultMessageListenerContainer;

import com.kuake.component.QueueMsgListener;
/**
 * 	<!-- 配activemq -->
	<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
	<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://192.168.25.128:61616" />
	</bean>
	<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
	<bean id="connectionFactory"
		class="org.springframework.jms.connection.SingleConnectionFactory">
		<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
		<property name="targetConnectionFactory" ref="targetConnectionFactory" />
	</bean>
	<!--这个是队列目的地,点对点的 -->
	<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg>
			<value>spring-queue</value>
		</constructor-arg>
	</bean>
	<!--这个是主题目的地,一对多的 -->
	<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg value="Itemtopic" />
	</bean>
	<!-- 消息监听器 -->
	<bean id="mytestmessage" class="com.e3shop.search.message.Mytestmessage"/>
	<!-- 消息监听容器 -->
	
	<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="queueDestination" />
		<property name="messageListener" ref="mytestmessage" />
	</bean>
	<bean id="itemListenerMessage" class="com.e3shop.search.message.ItemListenerMessage"></bean>
	<!-- 消息监听容器 -->
	<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="topicDestination" />
		<property name="messageListener" ref="itemListenerMessage" />
	</bean>
	参照,xml配置的方法 进行配置
 * 
 * @author Hao
 * @date: 2019年6月9日 下午1:56:23 
 * @Description:配置消费者
 */
@ComponentScan(basePackages={"com.kuake"})
@EnableJms
@Configuration
@PropertySource("classpath:conf.properties")
public class ConsumerConfig {
	@Value("${activemq.url}")
	String URL;
	
	@Value("${activemq.queueName}")
	String QUEUE_NAME;
	
	@Value("${activemq.topicName}")
	String TOPIC_NAME;

	@Bean
	//配置ConnectionFactory用于生成connection
	public ActiveMQConnectionFactory connectionFactory(){
		ActiveMQConnectionFactory activeMQConnectionFactory
										= new ActiveMQConnectionFactory(URL);
		return activeMQConnectionFactory;
	}
	
	@Bean
	//注册SingleConnectionFactory,这个spring的一个包装工厂 用于管理真正的ConnectionFactory
	public SingleConnectionFactory singleConnectionFactory(ActiveMQConnectionFactory activeMQconnectionFactory){
		SingleConnectionFactory connectionFactory = new SingleConnectionFactory();
		//设置目标工厂
		connectionFactory.setTargetConnectionFactory(activeMQconnectionFactory);
		return connectionFactory;
	}
	
		
		/*在xml当中的如下配置 效果相同
		 * <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		 *		<property name="connectionFactory" ref="connectionFactory" />
		 *		<property name="destination" ref="topicDestination" />
		 *		<property name="messageListener" ref="itemListenerMessage" />
		 *	</bean>
		 **/
	
	@Bean //配置topic监听容器,从ioc容器当中注入 ConnectionFactory  和 queueMsgListener
	public DefaultMessageListenerContainer defaultMessageListenerContainer2(SingleConnectionFactory singleConnectionFactory,TopicMsgListener topicMsgListener,Destination destination){
		//创建容器
		DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
		//设置监听器
		container.setMessageListener(topicMsgListener);
		//设置连接工厂
		container.setConnectionFactory(singleConnectionFactory);
		//设置监听目的地的名字/也可以直接设置对象目的地
		container.setDestination(destination);
		return container;
	}
	
	/**
	 * 配置队列目的的: 测试的时候 根据需要配置其中一个
	 * 	1.队列  点对点 queue
	 *  2.主题  一对多  topic
	 * */
	@Bean 
	public ActiveMQQueue queueDestination(){
		ActiveMQQueue activeMQQueue = new ActiveMQQueue(QUEUE_NAME);
		return activeMQQueue;
	}
	
	@Bean
	public ActiveMQTopic topicDestination(){
		ActiveMQTopic activeMQTopic = new ActiveMQTopic(TOPIC_NAME);
		return activeMQTopic;
	}
}

点对点监听器:

/**
 * 
 * 
 * @author Hao
 * @date: 2019年6月9日 下午2:03:11 
 * @Description:队列消息的 接受者
 */
@Component
public class QueueMsgListener implements MessageListener{
	
	
		/*
		 * @JmsListener(containerFactory="defaultMessageListenerContainer",destination="queueDestination")
		 * 经过测 发现这种方式 声明 监听的消费 者无效。几经探究,无果。
		 * */	
	public void onMessage(Message message){
		TextMessage textMessage = (TextMessage) message;
		System.out.println("queue监听者正在监听消息.............");
		try {
			System.out.println("监听者监听到消息"+textMessage.getText());
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

订阅监听器

package com.kuake.component;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
/**
 * 
 * 
 * @author Hao
 * @date: 2019年6月9日 下午3:48:06 
 * @Description: 一对多监听容器
 */
public class TopicMsgListener implements MessageListener{

	@Override
	public void onMessage(Message message) {
		TextMessage textMessage = (TextMessage) message;
		System.out.println("topic监听者正在监听消息.............");
		try {
			System.out.println("topic监听者监听到消息"+textMessage.getText());
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

(5)开始单元测试

package com.kuake.test;

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

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import com.kuake.config.ProducerConfig;

public class DemoTest {
	
	//测试点对点
	@Test
	public void testActiveMq(){
		AnnotationConfigApplicationContext aContext = 
				new AnnotationConfigApplicationContext(ProducerConfig.class);
		//获得发送者的模板对象
		JmsTemplate jmsTemplate = aContext.getBean(JmsTemplate.class);
		
		Destination bean = (Destination) aContext.getBean("queueDestination");
		
		//发送消息
		jmsTemplate.send(bean, new MessageCreator() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				TextMessage message = session.createTextMessage();
				message.setText("this is a activemq  message for queue");
				return message;
			}
		});
	}
	
	//测试topic发送
	@Test
	public void testActiveMq2(){
		AnnotationConfigApplicationContext aContext = 
				new AnnotationConfigApplicationContext(ProducerConfig.class);
		//获得发送者的模板对象
		JmsTemplate jmsTemplate = aContext.getBean(JmsTemplate.class);
		
		Destination bean = (Destination) aContext.getBean("topicDestination");
		
		//发送消息
		jmsTemplate.send(bean, new MessageCreator() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				TextMessage message = session.createTextMessage();
				message.setText("this is a activemq  message for topic");
				return message;
			}
		});
	}
	
}

**先进行点对点的生成者测试:**执行testActiveMq控制台打印如下:大致可以知道,消息发送出去了
在这里插入图片描述
进入ActiveMQ的控制台
在这里插入图片描述
可以看出有一个入对列的消息,因为我们没有接收者监听,所有Number of Consumers的数量是 0 。进入这个消息队列,查看详细信息。
在这里插入图片描述
消息详情就是生产者风发送过来的消息。
现在消费者开始上场,看是否能消费到该消息。测试代码:

package com.kuake.test;

import java.io.IOException;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.kuake.config.ConsumerConfig;


public class DemoTest {
	@Test
	public void testConsumerForQueue() throws IOException{
		AnnotationConfigApplicationContext aContext = 
				new AnnotationConfigApplicationContext(ConsumerConfig.class);
		//等待键盘输入 ,保持处于监听状态
		System.in.read();
	}
	
	@Test
	public void testConsumerForTopic() throws IOException{
		AnnotationConfigApplicationContext aContext = 
				new AnnotationConfigApplicationContext(ConsumerConfig.class);
		//等待键盘输入 ,保持处于监听状态
		System.in.read();
	}
	
	@Test
	public void testConsumerForTopic2() throws IOException{
		AnnotationConfigApplicationContext aContext = 
				new AnnotationConfigApplicationContext(ConsumerConfig.class);
		//等待键盘输入 ,保持处于监听状态
		System.in.read();
	}
}

测试testConsumerForQueue控制台输出:
在这里插入图片描述
可以看到这个就是刚刚queue生产者,发送到消息队列的消息,现在已经监听者接收到(消费者),再次进入ActiveMQ控制台,看看,消费和生产状况如何。
在这里插入图片描述
对比之前发现,pending Messages(等待消息)的数量由 1 变为了0 ,number Consumersmessages dequeued的数量都从0 增加到1 说明有了一个消费者,并且消出队了一次。然后点进去查看一下详情发现,没有消息内容了,说明消息被消费了。
因为我代码设置了System.in.read();等待键盘输入,如果没有输入就一直处于监听状态,所有只要生产者一发送一个消息到消息队列,消费者这边就可以立马接收到。

进行一对多 ,topic主题发布测试,
这次我先让topic属于监听状态,先执行testConsumerForTopictestConsumerForTopic2,控制台如下:
在这里插入图片描述
一直处于监听状态,然后执行生产者的测试方法发布主题测试(topic)测试方法testActiveMq2进行消息发布,发布的内容是"this is a activemq message for topic"
监听测试的控制台打印结果如下:
在这里插入图片描述
在发布消息之后,监听者会立马收到消息,(接收消息有一个前提,就是要先订阅这个主题,也就是先进行监听,才能收到消息。如果发布主题之后,再进行监听,是不能收到消息的
进入ActiveMQ控制台
在这里插入图片描述

记录一下基本用法 方便自己以后复习。

有关参考书籍:《ActiveMQ in Action .pdf》

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值