简介
1.什么是消息中间件
消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进 程间的通信。对于消息中间件,常见的角色大致也就有 Producer(生产者)、Consumer(消 费者)
2.常见的消息中间件
(1)**ActiveMQ**
ActiveMQ 是 Apache 出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完 全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现。
(2)RabbitMQ
AMQP 协议的领导实现,支持多种场景。淘宝的 MySQL 集群内部有使用它进行通讯, OpenStack 开源云平台的通信组件,最先在金融行业得到运用。
(3)ZeroMQ
史上最快的消息队列系统
(4)Kafka
Apache 下的一个子项目 。特点:高吞吐,在一台普通的服务器上既可以达到 10W/s 的吞吐速率;完全的分布式系统。适合处理海量数据。
JMS
1 简介
JMS(Java Messaging Service)是 Java 平台上有关面向消息中间件的技术规范,它便 于消息系统中的 Java 应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的 接口简化企业应用的开发。
JMS 本身只定义了一系列的接口规范,是一种与厂商无关的 API,用来访问消息收发系 统。它类似于 JDBC(java Database Connectivity):这里,JDBC 是可以用来访问许多不同关 系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。
许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA 的 Weblogic JMS service 和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或 路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对 象,由两部分组成:报头和消息主体。
报头 由路由信息以及有关该消息的元数据组成。
消息 主体则携带着应用程序的数据或有效负载
2 消息正文格式:
· TextMessage—一个字符串对象
· MapMessage—一套名称-值对
· ObjectMessage—一个序列化的 Java 对象
· BytesMessage—一个字节的数据流
· StreamMessage **— Java 原始值的数据流
3 消息传递类型
点对点消息类型下,如果没有消费者,队列会将消息存储,在消费者连接的时候将消息发送给消费者.如果由两个或以上的消费者监听同一个队列,使用轮询的模式进行消息处理
发布模式类型下,不管有没有消费者监听,容器都会将消息发布出去,有多少个消费者就会由多少个消费者接收到消息.
**一种是点对点的,即一个消息只能由一个消费者消费;
另一种是发布/ 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
ActiveMQ
1.下载
官方网站下载:http://activemq.apache.org/
2.安装(Linux) 和启动
**(1)将 下载好的apache-activemq-5.12.0-bin.tar.gz 上传至服务器
(2)解压此文件
tar zxvf apache-activemq-5.12.0-bin.tar.gz
(3)为 apache-activemq-5.12.0 目录赋权
chmod 777 apache-activemq-5.12.0
(4)进入 apache-activemq-5.12.0\bin 目录
(5)赋与执行权限
chmod 755 activemq
(6) 启动
./activemq start
启动成功:
访问管理页面
http://ip:8161/ 进入中管理页面
登陆:
默认用户名和密码
admin,admin
各列的含义:
Number Of Pending Messages :等待消费的消息 这个是当前未出队列的数量。
Number Of Consumers :消费者 这个是消费者端的消费者数量
Messages Enqueued :进入队列的消息 进入队列的总数量,包括出队列的。
Messages Dequeued :出了队列的消息 可以理解为是消费这消费掉的数量
入门Demo
准备:
引入依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.13.4</version>
</dependency>
Queue
1.创建queue消息生产对象
public class QueueProducer {
public static void main(String[] args) throws JMSException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.128:61616");
//2.获取连接
Connection connection = connectionFactory.createConnection();
//3.启动连接
connection.start();
//4.获取 session (参数 1:是否启动事务,参数 2:消息确认模式)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5.创建队列对象
Queue queue = session.createQueue("test-queue");
//6.创建消息生产者
MessageProducer producer = session.createProducer(queue);
//7.创建消息
TextMessage textMessage = session.createTextMessage("欢迎使用消息中间件");
//8.发送消息
producer.send(textMessage);
//9.关闭资源
producer.close();
session.close();
connection.close();
}
}
第四步中参数的类型
2.创建queue消息消费者
//1.创建连接工厂
ConnectionFactory connectionFactory=new
ActiveMQConnectionFactory("tcp://192.168.25.135:61616");
//2.获取连接
Connection connection = connectionFactory.createConnection();
//3.启动连接
connection.start();
//4.获取 session (参数 1:是否启动事务,参数 2:消息确认模式)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5.创建队列对象
Queue queue = session.createQueue("test-queue");
//6.创建消息消费
MessageConsumer consumer = session.createConsumer(queue);
//7.监听消息
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
TextMessage textMessage=(TextMessage)message;
try {
System.out.println("接收到消息:"+textMessage.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
//8.等待键盘输入
System.in.read();
//9.关闭资源
consumer.close();
session.close();
connection.close();
3.运行结果
Topic
1.创建topic生产者
public class TopicProducer {
public static void main(String[] args) throws JMSException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.135:61616");
//2.获取连接
Connection connection = connectionFactory.createConnection();
//3.启动连接
connection.start();
//4.获取 session (参数 1:是否启动事务,参数 2:消息确认模式)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5.创建主题对象
Topic topic = session.createTopic("test-topic");
//6.创建消息生产者
MessageProducer producer = session.createProducer(topic);
//7.创建消息
TextMessage textMessage = session.createTextMessage("欢迎使用消息中间件服务");
//8.发送消息
producer.send(textMessage);
//9.关闭资源
producer.close();
session.close();
connection.close();
}
}
2创建topic消费者
public class TopicConsumer {
public static void main(String[] args) throws JMSException, IOException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.135:61616");
//2.获取连接
Connection connection = connectionFactory.createConnection();
//3.启动连接
connection.start();
//4.获取 session (参数 1:是否启动事务,参数 2:消息确认模式)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5.创建主题对象
//Queue queue = session.createQueue("test-queue");
Topic topic = session.createTopic("test-topic");
//6.创建消息消费
MessageConsumer consumer = session.createConsumer(topic);
//7.监听消息
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("接收到消息:" + textMessage.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
//8.等待键盘输入
System.in.read();
//9.关闭资源
consumer.close();
session.close();
connection.close();
}
}
运行结果:
注意:
需要先启动消费者才会收到消息
spring整合消息中间件
1.准备
创建两个maven项目,同时导入依赖坐标
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<!-- jms -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<!-- activate mq -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.13.4</version>
</dependency>
</dependencies>
2.Queue生产者项目
2.1resources/spring/applicationContext-jms-producer.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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注解扫描 -->
<context:component-scan base-package="com.moonhu.demo"></context:component-scan>
<!-- 真正可以产生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>
<!--1.这个是队列目的地,点对点的 文本信息-->
<bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
<!-- 队列名称 -->
<constructor-arg value="queue_text"/>
</bean>
<!--2.这个是订阅模式 文本信息-->
<bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic_text"/>
</bean>
</beans>
2.2QueueDemo
@Component
public class QueueDemo {
/**
* 模板
*/
@Autowired
private JmsTemplate jmsTemplate;
/**
* 容器
*/
@Autowired
private Destination queueTextDestination;
/**
* 发送文本消息
*
* @param text
*/
public void sendTextMessage(final String text) {
// 发送消息
jmsTemplate.send(queueTextDestination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
// 创建文本信息
return session.createTextMessage(text);
}
});
}
}
2.3测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext-jms-producer.xml")
public class QueueTest {
@Autowired
private QueueDemo queueDemo;
@Test
public void testSend() {
queueDemo.sendTextMessage("SpringJms-点对点");
}
}
3.Queue消费者项目
3.1resources/spring/applicationContext-jms-consumer.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 真正可以产生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="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue_text"/>
</bean>
<!-- 我的监听类 -->
<bean id="queueListener" class="com.moonhu.demo.QueueListener"/>
<!-- 消息监听容器 -->
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="queueTextDestination"/>
<property name="messageListener" ref="queueListener"/>
</bean>
</beans>
3.2QueueListener
public class QueueListener implements MessageListener {
/**
* MessageListener接口的抽象方法
*
* @param message 接收的数据
*/
public void onMessage(Message message) {
// 数据强转
TextMessage textMessage = (TextMessage) message;
try {
// 获取数据并输出
System.out.println("接收到消息:" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
3.3测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/applicationContext-jms-consumer.xml")
public class QueueTest {
/**
* Queue消费者测试方法
*/
@Test
public void testReceive() {
try {
// 只需要使程序不结束监听数据即可
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.4测试结果
4.Topic生产者
4.1resources/spring/applicationContext-jms-producer.xml
需要有Topic的ActiveMQTopicbean对象
<!--2.这个是订阅模式 文本信息-->
<bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic_text"/>
</bean>
4.2TopicDemo
@Component
public class TopicDemo {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Destination topicTextDestination;
/**
* 发送文本消息
*
* @param text
*/
public void sendTextMessage(final String text) {
jmsTemplate.send(topicTextDestination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(text);
}
});
}
}
4.3测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext-jms-producer.xml")
public class TopicTest {
@Autowired
private TopicDemo topicDemo;
/**
* Topic发送消息测试
*/
@Test
public void testSend(){
// 发送消息
topicDemo.sendTextMessage("Topic-send-test");
}
}
5.Topic消费者
5.1resources/spring/applicationContext-jms-consumer.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 真正可以产生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="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue_text"/>
</bean>
<!-- 我的监听类 -->
<bean id="queueListener" class="com.moonhu.demo.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="queue_text"/>
</bean>
<!-- 我的监听类 -->
<bean id="topicListener" class="com.moonhu.demo.TopicListener"/>
<!-- 消息监听容器 -->
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="topicTextDestination"/>
<property name="messageListener" ref="topicListener"/>
</bean>
<!-- 发布的方法结束 -->
</beans>
5.2TopicListener
/**
* Topic消费者的监听类
*/
public class TopicListener implements MessageListener {
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("接收到的消息: " + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
5.3测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext-jms-consumer.xml")
public class TopicTest {
@Test
public void testReceive() {
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.4测试结果
6.SpringBoot整合ActivateMQ
6.1. 引入相关依赖:
<properties>
<!-- 指定java版本 -->
<java.version>1.7</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<dependencies>
<!-- springBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- 整合activateMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
</dependencies>
6.2. 创建引导类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/***
* 引导类
*/
@SpringBootApplication
public class SpringBootDemo {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo.class, args);
}
}
6.3创建控制类
@RestController
public class HelloWordTest {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
/**
* activate发消息测试
*/
@RequestMapping("/sendMsg")
public void sendMessage() {
jmsMessagingTemplate.convertAndSend("boot", "hello,你好");
}
}
6.4创建消费者类
创建消费者1
/**
* 监听器
*/
@Component
public class ConsumeDemo1 {
/**
* 接收消息
*
* @param msg
*/
@JmsListener(destination = "boot")
public void getMessage(String msg) {
System.out.println(msg+1);
}
}
创建消费者2
/**
* 监听器
*/
@Component
public class ConsumeDemo2 {
/**
* 接收消息
*
* @param msg
*/
@JmsListener(destination = "boot")
public void getMessage(String msg) {
System.out.println(msg+2);
}
}
6.5启动引导类
6.6 访问地址查看结果
http://localhost:8080/sendMsg
多次访问后输出结果
解析:
在spring的spring-boot-starter-activemq的依赖中,传递依赖了ActivateMQ的包不需要连接远端的ActivateMq服务器即可实现消息的发送和接收,使用的是内置的服务.发送的是Queue消息
如果要使用自己部署的服务器需要在配置文件中指定ActivateMQ的地址
spring.activemq.broker-url=tcp://192.168.25.128:61616
注意:
key值不能改变
思考
消费者接收不到消息
1.生产者和消费者桶名称不同