基本概述
模块之间的依赖也称之为耦合。而耦合越多,之后的维护工作就越困难。改善系统模块调用关系、减少模块之间的耦合的一种解决方案----消息中间件。
什么是消息中间件?
消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见的角色有Producer(生产者)Consumer(消费者)
ActiveMQ
ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。
什么是JMS
JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
这套规范一是定义了五种不同的消息正文格式,二是规定了消息传递类型的类型:点对点和发布订阅
JMS 定义的五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收不同形式的数据。
- TextMessage–一个字符串对象
- MapMessage–一套名称-值对
- ObjectMessage–一个序列化的 Java 对象
- BytesMessage–一个字节的数据流
- StreamMessage – Java 原始值的数据流
消息传递的类型:
- 一种是点对点的,即一个生产者和一个消费者一一对应;
- 另一种是发布 / 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
ActiveMQ下载与安装
官方网站下载:http://activemq.apache.org/
(1)安装环境:jdk1.8
(2)将apache-activemq-5.15.8-bin.tar.gz 上传至服务器
(3)解压此文件
tar -xvf apache-activemq-5.15.8-bin.tar.gz -C /usr/local
(4)进入apache-activemq-5.14.5\bin目录
(5)启动
[root@localhost bin]# ./activemq start
关闭:
[root@localhost bin]# ./activemq stop
查看状态:
[root@localhost bin]# ./activemq status
ActiveMQ默认监听的端口是8161(web管理端口)、61616(tcp连接端口),输入以下命令来验证ActiveMQ是否监听了8161、61616端口
netstat -anotp | grep 8161
(6)打开浏览器输入地址
http://ip:8161/ 即可进入ActiveMQ管理页面
ActiveMQ 默认用户名和密码:
用户名:admin
密码:admin
可以在/conf/users.properties中寻找
Number Of Pending Messages:等待消费的消息 这个是当前未出队列的数量。
Number Of Consumers:消费者 这个是消费者端的消费者数量
Messages Enqueued:进入队列的消息 进入队列的总数量,包括出队列的。
Messages Dequeued:出了队列的消息 可以理解为是消费这消费掉的数量。
消息传递类型类型的点对点和发布订阅
队列消息(点对点)的接收端
- 队列消息 一定会被 某个接收端消息,不管接收端有没有提前启动
- 一个队列消息只能被一个接收端 接收
发布订阅(主题)消息的接收端
- 消息接收端需要 先订阅某个主题,才能收到该主题的消息
- 一个主题消息 可以被多个 接收端 接收
Spring整合JMS
消息发送方
创建一个jar工程springjms_producer
pom依赖配置
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.15.8</version>
</dependency>
</dependencies>
配置spring-jms-producer.xml,这个配置文件主要是配置activeMQ的连接信息,以及配置相关的bean,比如说JMS的工具类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"
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.xsd">
<context:component-scan base-package="com.weilinyang" />
<!-- 产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.2.123:61616" />
</bean>
<!-- Spring用于管理ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetConnectionFactory" />
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
<!-- 队列目的地,点对点信息 -->
<bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="spring_queue" />
</bean>
<!-- 主题目的地,发布订阅信息 -->
<bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="spring_topic" />
</bean>
</beans>
创建一个测试类Producer,注入我们刚刚在spring-jms-producer.xml配置的bean
@Component
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-*.xml")
public class Producer {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private ActiveMQQueue queue;
@Autowired
private ActiveMQTopic topic;
/*
测试发送队列消息
*/
@Test
public void sendQueue(){
jmsTemplate.send(queue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("你好!我是spring-jms发送的队列测试消息!");
}
});
}
/*
测试发送订阅消息
*/
@Test
public void sendTopic(){
jmsTemplate.send(topic, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("你好!我是spring-jms发送的发布订阅测试消息!");
}
});
}
}
消息接收方
创建一个jar工程springjms_consumer
pom依赖同上
配置spring-jms-producer.xml,这个配置文件主要是配置activeMQ的连接信息,以及自定义监听器以及接收消息的容器
每一个接收相关bean都包含目的地、监听类和消息监听容器的bean。
<?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.xsd">
<context:component-scan base-package="com.weilinyang" />
<!-- 产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.2.123:61616" />
</bean>
<!-- Spring用于管理ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetConnectionFactory" />
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
<!-- 队列目的地,点对点信息 -->
<bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="spring_queue" />
</bean>
<!--配置监听类-->
<bean id="queueListener" class="com.weilinyang.consumer.QueueListener"/>
<!-- 消息监听容器 -->
<bean
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueTextDestination" />
<property name="messageListener" ref="queueListener" />
</bean>
<!-- 主题目的地,发布订阅信息 -->
<bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="spring_topic" />
</bean>
<!--配置监听类-->
<bean id="topocListener" class="com.weilinyang.consumer.TopicListener"/>
<!-- 消息监听容器 -->
<bean
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="topicTextDestination" />
<property name="messageListener" ref="topocListener" />
</bean>
</beans>
自定义监听器类实现MessageListener类
public class QueueListener implements MessageListener {
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("接收到的队列消息是"+text);
}catch (Exception e){
e.printStackTrace();
}
}
}
public class TopicListener implements MessageListener {
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("接收到的订阅消息是"+text);
}catch (Exception e){
e.printStackTrace();
}
}
}
测试
创建一个测试类,加载进spring-jms-producer.xml,只要让这个测试类的测试方法一直运行,监听器就可以一直被运行,当监听器收到消息后会在控制台打出
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-*.xml")
public class ConsumerTest {
@Test
public void run(){
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行run方法进行监听
对点对点消息的测试
运行Producer类的sendQueue方法
对发布订阅消息的测试
运行Producer类的sendTopic方法