一、概念
1、JMS、AMQP
- JMS:JAVA消息服务,基于JVM消息代理的规范(ActiveMQ、HornetMQ)[两种模型:点对点、发布\订阅]
- AMQP:高级消息队列,兼容JMS(RabbitMQ是AMQP实现)[五种模型:direct exchange、fanout exchange、topic change、headers exchange、system exchange]
2、Spring支持
- spring-jsm提供对JMS支持
- spring-rabbit提供对AMQP支持
- 需要ConnectionFactory的实现连接消息代理
- 提供JmsTemplate、RabbitTemplate发送消息
- @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
- 用@EnableJms、@EnableRabbit开启支持
3、RabbitMQ简介
- exchange:交换机,用来接收生产者发送的消息并将这些消息路由给服务器中的队列,四种类型:direct、fanout、topic、headers
- Queue:消息队列,保存消息的容器,一个消息可以投入一个或多个队列,消息一直在队列中,等待消费者连接队列获取
- Binding:绑定,关联消息队列和交换机,一个绑定是基于路由键将交换机和消息队列连接起来的路由规则,队列和交换机是多对多的
- Connection:网络连接,比如一个TCP连接
- Channel:信道,信道是建立在真实的TCP连接内的虚拟连接
- Vitural Host:虚拟主机,每个虚拟主机是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定,虚拟主机之间是有隔离的
- Broker:表示消息队列服务器实体
☆实现过程:
Publisher发布消息—>消息给到服务器—>服务器将消息分配到其中的一个虚拟主机—>给到指定的交换器—>根据路由键及路由规则确定给哪个消息队列—>消费者与队列建立连接(每一个tcp连接建立多个信道节省资源)—>从消息队列中消费数据
二、RabbitMQ安装测试
1、安装
- 虚拟机中docker安装rabbitmq:
sudo docker pull rabbitmq:3-management
management版本自带web管理界面 - 启动rabbitmq:
sudo docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq +镜像id
5672:5672为主机的5672映射到docker容器的5672端口;15672:15672为管理界面访问web页面的端口映射 - 浏览器中输入虚拟机ip可以登录rabbitmq的web管理界面:192.168.0.104:15672
在web界面建立两个exchange和四个queue如下图所示,绑定路由键
定义交换器:
定义队列:
绑定队列和交换器:
topic模式下支持模糊匹配:“#”表示匹配0个或多个单词;“*”表示匹配一个单词
direct模式的交换器发送的消息只能发送到与其路由键相同的队列中
fanout模式的交换器可以发送到所有的队列中
topic模式的交换器只能发送到路由键与其模糊匹配的队列中
2、springboot中配置rabbitmq
rabbitmq的自动配置组件:
- RabbitAutoConfiguration 自动配置类
- 自动配置了连接工厂ConnectionFactory
- RabbitProperties封装了RabbitMQ的配置
- RabbitTemplate:模板类,给RabbitMQ发送和接受消息
- AmqpAdmin:RabbitMQ系统管理功能组件,可以声明队列和交换器
springboot与rabbitmq配置过程:
- (1)引入spring-boot-starter-amqp
- (2)application.properties配置
spring.rabbitmq.host=192.168.0.104
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#端口不写,默认也是5672
#spring.rabbitmq.port=5672
- (3)测试RabbitMQ(AmqpAdmin:管理组件、RabbitTemplate:消息发送处理组件)
在测试文件中:
发送消息:rabbitTemplate.convertAndSend(exchange,queue,object)
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBoot08AmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
Map<String,Object> map=new HashMap<>();
map.put("msg","haha");
map.put("data",Arrays.asList("hello ",123,true));
//只需传入要发送的对象,自动序列化发送给rabbitmq,object默认当成消息体
//对象被默认序列化后发送出去
rabbitTemplate.convertAndSend("exchange.direct", "atguigu.news", map); //定义路由器、路由键、要发送的数据对象
}
}
web界面上接受到的消息为:
测试文件中接受消息:rabbitTemplate.receiveAndConvert
@Test
public void receive() {
Object data=rabbitTemplate.receiveAndConvert("atguigu.news");
System.out.println(data);
}
如何将数据转为json发送出去,避免上面出现的乱码?
解决方法:自定义MessageConverter配置
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
在发送数据时会自动配置调用我们选择的MessageConverter方法
三、消息监听@RabbitListener
@RabbitListener和@EnableRabbit
@EnableRabbit添加在main主配置类中,开启rabbitmq的注解模式。监听消息队列的方法类需要被@Service注解,其方法需要被@RabbitListener注解,当监听的队列中有消息时,会自动出发该方法
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
import springboot.bean.Book;
@Service
public class BookService {
//监听来自消息队列中的内容,只要队列中有消息进来,方法就会调用
@RabbitListener(queues = "atguigu.news") //可以监听多个队列
public void receive(Book book) {
System.out.println("收到消息:"+book);
}
}
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableRabbit //开启基于注解的rabbitmq
@SpringBootApplication
public class SpringBoot08AmqpApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot08AmqpApplication.class, args);
}
}
四、系统管理功能组件AmqpAdmin
AmqpAdmin:创建和删除Queue、Exchange、Binding
1、创建交换器
@Autowired
AmqpAdmin amqpAdmin;
@Test
public void createExchange() {
amqpAdmin.declareExchange(new DirectExchange("exchange", true, true)); //交换器名字、是否持久化、是否自动删除
System.out.println("创建成功");
}
declareExchange:创建交换器
DirectExchange:direct模式的交换器
2、创建队列
@Test
public void createQueue() {
amqpAdmin.declareQueue(new Queue("queue", true))
System.out.println("创建成功");
}
3、创建绑定规则
需要规定:目的地(队列名字)、目的地类型、需要绑定的交换器名字、路由键
new Binding(destination, destinationType, exchange, routingKey, arguments)
@Test
public void bind() {
amqpAdmin.declareBinding(new Binding("queue", Binding.DestinationType.QUEUE, "exchange", "queue", null));
}
4、删除队列或者交换器
只需指定需要删除的度列或者交换器的名字
amqpAdmin.deleteQueue("queue");