大多数应用中,可通过消息服务中间件来提升系统异步通信,扩展解耦能力
等同于注册用户将注册信息写入数据库,再以极短的时间写入消息队列。立马就可以返回消息给用户。然后发送邮件和发送短信的这些操作。再通过异步从消息队列中读取信息,进行操作
订单系统–消息队列–库存系统
比如10万个请求直接访问数据库不行,就让他直接访问消息队列。消息队列可设置它最多处理1万条信息。将其余9万条挡掉,秒杀失败。然后再处理秒杀业务
message 消息
destination 目的地
点对点模式:
消息只有唯一的发送者和接受者。但并不是只有一个接收者。
同一时间,一个发送者发送消息到消息队列。多个消费者可以享受接收这个消息的权利。但只能有一个消费者消费这条信息
发布订阅模式:
发布者发送消息到topic。多个接收者订阅这主题。接收者能同时收到消息
jms
基于JVM消息代理的规范,不能跨平台跨语言的。activeMq
AMQP
高级消息队列协议,兼容JMS的,rabbitmq是AMQP的实现
跨平台,跨语言。发送数据都是以byte[]将消息序列化后发送
rabbitmq的springboot starter是 spring-boot-starter-amqp
message
消息:由消息头和消息体组成
publisher
消息的生产者,也是将message发送至Exchange
Exchange
交换器:用于接收生产者发送的消息并将这些消息路由给服务器的队列
Queue
队列:保存消息直到发送给消费者
Binding
绑定:路由键将交换器和队列连接起来的路由规则
connection
网络连接:比如tcp连接
channel
信道:发送数据,订阅队列,接受消息的通道
amqp跟jms的差别就是多了binding跟exchange
exchange有四种策略:direct,fanout,topic和headers,只有header不是通过路由键绑定,而是通过消息头
1,direct:转发,交换器的key和queue的key相同才会转发
2,fanout:交换器是fanout则广播所有绑定的队列
3,topic是模糊匹配。exchange是路由键和绑定键的单词切分以.分隔。而queue是以#(匹配0或者多个单词)。*(匹配一个单词)。。例如:usa.news 匹配queue中的usa.#
1,hub.docker.com
2,docker pull rabbitmq:3.7.26-management
3,docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq rabbitmq:3.7.26-management
4,进入图形化界面,创建交换器:exchange.direct,exchange.fanout,exchange.topic
5,创建队列:atguigu,atguigu.news,atguigu.emps,gulixueyuan.news
6,回到exchange绑定路由键和queue (1)direct:queue:atguigu。rounting key:atguigu queue:atguigu.news routing key:atguigu.news queue:atguigu.emps routing key:atguigu.emps queue:gulixueyuan.news routing key:gulixueyuan.news #(2)fanout 交换器也是绑定这四个queue (3)topic queue:atguigu rounting key:atguigu.# (atguigu开头的routing key绑定atguigu.# new结尾的绑定 *.news一共绑5个)
7,测试direct
publish message选项填写routing key=atguigu payload为发送消息的内容随便写,点击发送。发现就一条队列收到消息,并且精确匹配。到atguigu
8,测试fanout
全收到消息
9,测试topic
routing key=atguigu.news 由于规则匹配atguigu.#和*.news的队列都能发过去。所以这边全部发过去
10,queue可以点击get message按钮获取到发送过来的消息,默认是nack。。。就接受一条发送过来的消息。如果选择ack,则删除掉本条消息,再获取下一条消息
11,项目整合rabbitmq
1,
org.springframework.boot
spring-boot-starter-amqp
2.1.13.RELEASE
com.fasterxml.jackson.core
jackson-databind
2.9.5
2,
spring.rabbitmq.host=xxxx
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
3,test类
package com.atguigu.springboot02amqp;
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;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
@RunWith(SpringRunner.class)
public class Springboot02AmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void contextLoads() {
//点对点模式
//rabbitmq有两种方法消息的方法
//1,rabbitTemplate.send(exChange,routekey,message)
//2,rabbitTemplate.covertAndSend(exchange,routekey,Object)
Mapmap=new HashMap<>();
map.put("msg","这是第一个消息");
map.put("data", Arrays.asList("helloworld",123,true));
rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",map);
}
}
这时候直接去rabbit里面去get消息。发现是序列化策略不对的
4,test类继续
写一个receive的方法
@Test
public void receive(){
Object o=rabbitTemplate.receiveAndConvert("atguigu.news");
System.out.println(o.getClass());
System.out.println(o);
}
发现可以读取到控制台。并且消费了消息。但是图形化界面的序列化机制有些不对。怎么改成json的
5,config
package com.atguigu.springboot02amqp.config;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
6,这下发送消息和取消息都正常了
7,rabbitmq操作java-bean
package com.atguigu.springboot02amqp.bean;
public class Book {
private String bookName;
private String author;
Book(){}
public Book(String bookName, String author) {
this.bookName = bookName;
this.author = author;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", author='" + author + '\'' +
'}';
}
}
修改test类
package com.atguigu.springboot02amqp;
import com.atguigu.springboot02amqp.bean.Book;
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;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
@RunWith(SpringRunner.class)
public class Springboot02AmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void contextLoads() {
//点对点模式
//rabbitmq有两种方法消息的方法
//1,rabbitTemplate.send(exChange,routekey,message)
//2,rabbitTemplate.covertAndSend(exchange,routekey,Object)
Mapmap=new HashMap<>();
map.put("msg","这是第一个消息");
map.put("data", Arrays.asList("helloworld",123,true));
rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",new Book("java 8新特性","ljs"));
}
@Test
public void receive(){
Object o=rabbitTemplate.receiveAndConvert("atguigu.news");
System.out.println(o.getClass());
System.out.println(o);
}
}
8,广播队列(不用管rountkey)
修改test类
9,生产者消费者监听问题
package com.atguigu.springboot02amqp.service;
import com.atguigu.springboot02amqp.bean.Book;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@RabbitListener(queues = "atguigu.news")
public void receive(Book book){
System.out.println("收到消息:"+book);
}
}
@RabbitListener(queues = "atguigu")
public void receive02(Message message){
System.out.println(message.getBody());
System.out.println(message.getMessageProperties());
}
10,以上是本来rabbitMQ已经创建好了exchange和queue。如果没创建。则使用AmqpAdmin操作消息
test类
//创建exchange
@Test
public void createExchange(){
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
System.out.println("创建交换器完成");
}
//创建queue
@Test
public void createQueue(){
amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true));
}
//将创建出的交换器跟队列绑定
@Test
public void binding(){
amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp:haha",null));
}
exchange参数:指定名称,是否持久化,是否自动删除。queue一样。binding:从左到右:绑定的队列名称,绑定队列,exchange名称,路由键随便写,消息可以指定null
#####rabbitMQ的自动配置
1,rabbitAutoConfiguration
2,有自动配置了连接工厂ConnectionFactory
3,rabbitProperties封装了rabbitMQ的配置
4,rabbitTemplate,给rabbitMq发送和接受消息
5,AmqpAdmin:rabbitMq系统管理功能组件