SpringBoot与消息
JMS & AMPQ简介
1、消息服务中两个重要的概念:消息代理和目的地
当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地
2、消息队列主要有两种形式的目的地
(1) 队列(queue):点对点消息通信,只能有唯一的发送者和接受者,但不一定只能有一个接收者
(2) 主题(topic): 发布(publish)/订阅(subscribe)消息通信,多个接收者监听主题,会在消息到达同时接收到消息
3、JMS(Java Message Service):JAVA消息服务,基于JVM消息代理的规范,ActiveMQ、HornetMQ是JMS的实现
4、AMQP(Advanced Message Queuing Protocol)
(1) 高级消息队列协议,也是一个消息代理的规范,兼容JMS
(2) RabbitMQ是AMQP的实现
|
JMS |
AMQP |
定义 |
Java api |
Wire-protocol |
跨语言 |
否 |
是 |
跨平台 |
否 |
是 |
Model |
提供两种消息模型: (1)、Peer-2-Peer (2)、Pub/sub |
提供了五种消息模型: (1)、direct exchange (2)、fanout exchange (3)、topic change (4)、headers exchange (5)、system exchange 本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分; |
支持消息类型 |
多种消息类型: TextMessage MapMessage BytesMessage StreamMessage ObjectMessage Message (只有消息头和属性) |
byte[] 当实际应用时,有复杂的消息,可以将消息序列化后发送。 |
综合评价 |
JMS 定义了JAVA API层面的标准;在java体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差; |
AMQP定义了wire-level层的协议标准;天然具有跨平台、跨语言特性。 |
RabbitMQ简介
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现
基本概念
- P: 为Producer,数据的发送方,生产者。
- C:为Consumer,数据的接收方,消费者。
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
- channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
RabbitMQ运行机制
AMQP中的消息的路由过程和JMS存在一些差别,AMQP中增加了Exchange和Binding的角色。生产者把消息发布到Exchange上,消息最终到达队列并被消费者接收,而Binding决定交换器的消息应该发送到哪个队列
Exchange类型:
Exchange分发消息时根据类型的不同分发策略有区别,目前共有四种类型:direct、fanout、topic、headers。其中headers不是使用路由键匹配AMQP消息。且headers交换器和direct交换器完全一致,但是性能差很多,目前几乎用不到了
整合RabbitMQ
创建项目,选中RabbitMQ模块
配置RabbitMQ
在配置文件中配置rabbitMQ
spring: rabbitmq: host: 172.17.119.176 username: guest password: guest port: 5672 # virtual-host:
使用RabbitTemplate操作消息
@Autowired RabbitTemplate rabbitTemplate; @Test public void contextLoads() { // Message: 需要自己构造一个消息,定义消息体内容和消息头 // rabbitTemplate.send(exchange, routeKey, message); // 只需要传入要发送的对象,自动序列化发送,object默认被当做消息体 // rabbitTemplate.convertAndSend(exchange, routeKey, object); Map<String, Object> map = new HashMap<>(); map.put("msg", "这是一条消息"); map.put("list", Arrays.asList("hello", 123, true)); rabbitTemplate.convertAndSend("exchange.direct", "atguigu.news", map); } /** * 接收消息 */ @Test public void receive(){ Object o = rabbitTemplate.receiveAndConvert("atguigu.news"); System.out.println(o.getClass()); System.out.println(o); }
序列化机制
在发送消息的时候,接收到的数据是按照JDK序列化后的,会显得很乱,就像下面这样:
那么如何将接收到的数据自动转换成json发送出去呢?
其实只需要在配置类中添加我们自己得序列化规则即可
@Bean public MessageConverter messageConverter(){ return new Jackson2JsonMessageConverter(); }
在发消息接收到后就是json格式了
@RabbitListener & @EnableRabbit
@EnableRabbit + @RabbitListener可以监听消息队列的内容
①、首先要在主程序类上标注@EnableRbbit开启消息监听
@EnableRabbit @SpringBootApplication public class RabbitmqApplication { public static void main(String[] args) { SpringApplication.run(RabbitmqApplication.class, args); } }
②、然后在要监听消息的方法上标注@RabbitListener,并指定要监测的消息队列即可,只要队列接收到了消息就会执行该方法
@RabbitListener(queues = "atguigu.news") // 监听atguigu.news队列的消息 public void receive(Book book){ System.out.println("接收消息" + book); }
还可以使用Message监听消息的头信息和消息体信息
@RabbitListener(queues = "atguigu.news") public void receive02(Message message){ // 消息体 System.out.println(message.getBody()); // 消息头信息 System.out.println(message.getMessageProperties()); }
AmqpAdmin管理组件的使用
之前的交换器跟队列都是在rabbitmq的web界面手动创建的
创建Exchange:
创建队列:
绑定交换器跟队列:
那么怎样在程序中创建这些呢?
这就需要使用AmqpAdmin去管理RabbitMQ的组件,它可以帮我们创建和删除Queue,Exchange,Binding
创建交换器:
需要使用DirectExchange去创建,然后使用AmqpAdmin去添加
@Autowired AmqpAdmin amqpAdmin; @Test public void createExchange(){ amqpAdmin.declareExchange(new DirectExchange("amqpadmin.directexchange")); }
创建其他的交换器只需要将创建exchange的类换一下即可
删除交换器:
@Test public void createExchange(){ amqpAdmin.deleteExchange("amqpadmin.directexchange"); }
创建队列:
@Autowired AmqpAdmin amqpAdmin; @Test public void createQueue(){ // amqpAdmin.declareQueue(); // 什么都不写会自动生成对列名 // 第一个参数:队列的名字。第二个参数:是否持久化 amqpAdmin.declareQueue(new Queue("amqpadmin.queue", true)); }
删除队列:
@Test public void createQueue(){ amqpAdmin.deleteQueue("amqpadmin.queue"); }
绑定交换器与队列:
@Autowired AmqpAdmin amqpAdmin; @Test public void bind(){ /** * 参数一:目的地,即要绑定的队列或交换器 * 参数二:类型,绑定的是队列还是交换器 * 参数三:交换器的名字 * 参数四:路由键 * 参数五:null */ amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE, "amqpadmin.directexchange", "amqpadmin.haha", null)); }
解绑:
@Autowired AmqpAdmin amqpAdmin; @Test public void bind(){ /** * 参数一:目的地,即要绑定的队列或交换器 * 参数二:类型,绑定的是队列还是交换器 * 参数三:交换器的名字 * 参数四:路由键 * 参数五:null */ amqpAdmin.removeBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE, "amqpadmin.directexchange", "amqpadmin.haha", null)); }