任务异步处理将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。
应用程序解耦合MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用MQ能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
系统的一部分组件失效时,不会影响到整个系统。MQ降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
是一种协议,更准确的说是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。
即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。JMS规定了两种消息模式;而AMQP的消息模式更加丰富.
1、生产者和Broker建立TCP连接。
2、生产者和Broker建立通道。
3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4、Exchange将消息转发到指定的Queue(队列)
1、消费者和Broker建立TCP连接
2、消费者和Broker建立通道
3、消费者监听指定的Queue(队列)
4、当有消息到达Queue时Broker默认将消息推送给消费者。
5、消费者接收到消息。
docker pull rabbitmq:management
docker run -di --name=myrabbitmq -p 5671:5617 -p 5672:5672 -p4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq:management
15672 (if management plugin is enabled.管理界面 )
15671 management监听端口
5672, 5671 (AMQP 0-9-1 without and with TLS 消息队列协议是一个消息协议)
4369 (epmd) epmd 代表 Erlang 端口映射守护进程
25672 (Erlang distribution)
浏览器中输入地址
http://服务器ip:15672/
docker update --restart=always 容器ID
RabbitMQ在安装好后,可以访问http://服务器ip:15672;其自带了guest/guest的用户名和密码;如果需要创建自定义用户;那么也可以登录管理界面后,如下操作:
角色说明:
像mysql拥有数据库的概念并且可以指定用户对库和表等操作的权限。RabbitMQ也有类似的权限管理;在RabbitMQ中可以虚拟消息服务器Virtual Host,每个Virtual Hosts相当于一个相对独立的RabbitMQ服务器,每个VirtualHost之间是相互隔离的。exchange、queue、message不能互通。相当于mysql的db。Virtual Name一般以/开头。
org.springframework.boot
spring-boot-parent
2.1.6.RELEASE
org.springframework.boot
spring-boot-starter-amqp
org.springframework.boot
spring-boot-starter-test
yml文件一样
spring:
rabbitmq:
host: 122.51.207.162
port: 5672
virtual-host: /laoshentou # 地址
username: # rabbitmq账号
password: # rabbitmq密码
各自创建springboot启动类
package com.rabbitmq.producer.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
/**
* 主题交换器的名称
*/
public static final String TOPIC_EXCHANGE = "topicExchange";
/**
* 搜索队列
*/
public static final String SEARCH_QUEUE = "searchQueue";
/**
* 插入队列
*/
public static final String INSERT_QUEUE = "insertQueue";
/**
* 通配符
*/
public static final String ROUTING_KEY = "it.#";
/**
* 主题模式交换机
*/
@Bean
public Exchange topicExchange() {
return new TopicExchange(TOPIC_EXCHANGE);
}
/**
* 搜索队列
*/
@Bean
public Queue searchQueue() {
return new Queue(SEARCH_QUEUE);
}
/**
* 插入队列
*/
@Bean
public Queue insertQueue() {
return new Queue(INSERT_QUEUE);
}
/**
* 主题交换机绑定搜索队列
*/
@Bean
public Binding bindingSearchQueueToTopicExchange() {
return BindingBuilder.bind(searchQueue()).to(topicExchange()).with(ROUTING_KEY).noargs();
}
/**
* 主题交换机绑定插入队列
*/
@Bean
public Binding bindingInsertQueueToTopicExchange() {
return BindingBuilder.bind(insertQueue()).to(topicExchange()).with(ROUTING_KEY).noargs();
}
}
package com.rabbitmq.producer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = ProducerApplication.class)
@RunWith(SpringRunner.class)
public class TestSimple {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 简单模式:一个生产者,一个消费者,不需要设置交换机(使用的是默认的交换机,routing key与队列名一致)
*/
@Test
public void testSimpleSend() {
//发消息,形参为指定的队列名和要发送的消息内容
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("simple_queue", "测试简单模式!" + i);
}
}
/**
* 工作队列模式:一个生产者,多个消费者(竞争关系),不需要设置交换机(使用的是默认的交换机,routing key与队列名一致)
*/
@Test
public void testWorkSend() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("work_queue", "work模式:" + i);
}
}
/**
* 广播模式/发布订阅模式
* 一个生产者发,多个消费者通过不同队列接,所有人都可以接到
* 需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列
*/
@Test
public void testPubAndSubSend() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("fanout_exchange", "", "发布订阅/广播模式:" + i);
}
}
/**
* 路由模式
* 需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key
* 当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
* - 交换机direct_exchange将routing key为insert的消息发给绑定了对应routing key的队列direct_queue_insert
* direct_exchange ==> routing key(insert) ==> direct_queue_insert
* direct_exchange ==> routing key(update) ==> direct_queue_update
*/
@Test
public void testDirectSend1() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("direct_exchange", "insertKey", "路由模式(insertKey):" + i);
}
}
@Test
public void testDirectSend2() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("direct_exchange", "updateKey", "路由模式(updateKey):" + i);
}
}
/**
* 通配符/主题模式
* 需要设置类型为topic的交换机,交换机和队列进行绑定,并且制定通配符方式的routing key
* 当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
* item后面加一个`.`的routing key(例如item.goods) 使用item.*可以接受
* item后面加一个或多个`.`的routing key(例如item.goods.spu) 使用item.#可以接受
* - 交换机topic_exchange将routing key为item.goods的消息发送到绑定的队列,routing key为item.*和item.#的队列都能接收到
* - 交换机topic_exchange将routing key为item.goods.spu的消息发送到绑定的队列,routing key为item.#的队列才能接收到
*/
@Test
public void testTopicSend1() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("topic_exchange", "item.goods", "通配符/主题模式(item.goods):" + i);
}
}
@Test
public void testTopicSend2() {
for (int i = 0; i < 5; i++) {
rabbitTemplate.convertAndSend("topic_exchange", "item.goods.spu", "通配符/主题模式(item.goods.spu):" + i);
}
}
}
简单模式
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "simple_queue")
public class SimpleListener {
@RabbitHandler
public void testListener(String message) {
System.out.println("简单模式:" + message);
}
}
工作队列模式1
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "work_queue")
public class WorkListener1 {
@RabbitHandler
public void testListener(String message) {
System.out.println("工作队列模式1:" + message);
}
}
工作队列模式2
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkListener2 {
@RabbitListener(queues = "work_queue")
public void testListener1(String message) {
System.out.println("工作队列模式2:" + message);
}
@RabbitListener(queues = "work_queue")
public void testListener2(String message) {
System.out.println("工作队列模式3:" + message);
}
}
发布订阅/广播模式
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class PubAndSunListener {
@RabbitListener(queues = "pubandsub1_queue")
public void testListener1(String message){
System.out.println("发布订阅/广播模式1:"+message);
}
@RabbitListener(queues = "pubandsub2_queue")
public void testListener2(String message){
System.out.println("发布订阅/广播模式2:"+message);
}
}
路由模式
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class DirectListener {
@RabbitListener(queues = "direct_queue_insert")
public void testListener1(String message) {
System.out.println("路由模式(insertKey):" + message);
}
@RabbitListener(queues = "direct_queue_update")
public void testListener2(String message) {
System.out.println("路由模式(updatekey):" + message);
}
}
通配符/主题模式
package com.rabbitmq.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class TopicListener {
@RabbitListener(queues = "topic_queue_item*")
public void testListener1(String message){
System.out.println("通配符/主题模式(item.goods):" + message);
}
@RabbitListener(queues = "topic_queue_item#")
public void testListener2(String message){
System.out.println("通配符/主题模式(item.goods.spu):" + message);
}
}
工作模式:
1、简单模式 HelloWorld : 一个生产者、一个消费者,不需要设置交换机(使用默认的交换机,routingKey与队列名一致)
2、工作队列模式 Work Queue: 一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认的交换机)
3、发布订阅模式 Publish/subscribe: 需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列
4、路由模式 Routing: 需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
5、通配符模式 Topic: 需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列