启动RabbitMQ管理插件
1.启动 RabbitMQ 管理插件。rabbitmq-plugins enable rabbitmq_management
rabbitmq-server # 直接启动,如果关闭窗⼝或需要在该窗⼝使⽤其他命令时应⽤就会停⽌rabbitmq-server -detached # 后台启动rabbitmq-server start # 启⽤服务rabbitmq-server restart # 重启服务rabbitmqctl status # 查看状态rabbitmqctl stop # 停⽌服务
<!-- RabbitMQ 启动依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- RabbitMQ测试依赖 -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
创建虚拟机。选择【Admin】-【Virtual Hosts】-【Add a new virtual host】选项,添加⼀个虚拟机
yml中导入依赖
spring:
# 配置RabbitMQ消息中间件连接配置
rabbitmq:
host: 192.168.48.67
port: 5672 # 编程端口(固定)
username: admin
password: 123456
virtual-host: /zhengchunbo # 配置RabbitMQ虚拟主机路径(默认为"/"可以省略)
一·Publish/Subscribe(发布订阅模式)
Spring Boot整合RabbitMQ中间件实现消息服务,主要围绕3个部分的⼯作进⾏展开:定制中间件、消息发送者发 送消息、消息消费者接收消息。其中,定制中间件是⽐较麻烦的⼯作,且必须预先定制。下⾯我们以⽤户注册成功 后同时发送邮件通知和短信通知这⼀场景为例, 分别使⽤基于API、基于配置类和基于注解这3种⽅式实现 Publish/Subscribe⼯作模式的整合。
.1基于配置类的⽅式
1.开RabbitMQ消息配置类RabbitMQConfig,在该配置类中使⽤基于配置类的⽅式定制消息发送相关组件。
package com.example.demo.collection.config;
import org.springframework.amqp.core.*;
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 RabbitMQConfig {
// //定制Json格式的消息转化器
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
/** 使⽤基于配置类的⽅式定制消息中间件 */
// 1.定义fanout类型的交换器
@Bean
public Exchange fanoutExchange() {
//创建一个fanout交换机 (发布订阅模式)
return ExchangeBuilder.fanoutExchange("fanout_exchange").build();
}
// 2.定义两个不同名称的消息队列
@Bean
public Queue fanoutQueueEmail() {
return new Queue("fanout_queue_email");
}
@Bean
public Queue fanoutQueueSms() {
return new Queue("fanout_queue_sms");
}
// 3.将两个不同名称的消息队列与交换器进⾏绑定
@Bean
public Binding bindingEmail() {
//消息队列------>绑定交换机 -------->有没有路由键---------->有没有其他参数
return BindingBuilder.bind(fanoutQueueEmail()).to(fanoutExchange()).with("").noargs();
}
@Bean
public Binding bindingSms() {
return BindingBuilder.bind(fanoutQueueSms()).to(fanoutExchange()).with("").noargs();
}
}
2.创建名为
com.ytx.service
的包,并在该包下创建⼀个针对
RabbitMQ
消息中间件进⾏消息接收
和处理的业务类
RabbitMQService
。
package com.ytx.chapter08.service;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
/** RabbitMQ消息接收处理的业务类 */
@Service
public class RabbitMQService {
/** Publish/Subscribe⼯作模式接收,处理邮件业务 */
@RabbitListener(queues = "fanout_queue_email")
public void subConsumerEmail(Message message) {
byte[] body = message.getBody();
String msg = new String(body);
System.out.println("邮件业务接收到消息:" + msg);
}
/** Publish/Subscribe⼯作模式接收,处理短信业务 */
@RabbitListener(queues = "fanout_queue_sms")
public void subConsumerSms(Message message) {
byte[] body = message.getBody();
String msg = new String(body);
System.out.println("短信业务接收到消息:" + msg);
}
}
3.发送测试
@Autowired
private RabbitTemplate rabbitAvailable;
@Test
public void subPublisher(){
User user = new User(6, "张三");
/**
*使用RabbitTemplate完成消息的发送:将消息指定发送给特性名称的交换机
* 参数1: 将消息发送给哪一个交换机
* 参数2:表示路由键
* 参数3: 表示发送的消息数据是什么
*/
rabbitAvailable.convertAndSend("fanout_exchange","",user);
}
三.2基于注解的⽅式
package com.example.demo.collection.service;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class RabbitService {
//
//发布订阅模式
//监听队列
@RabbitListener(bindings = @QueueBinding(
value =@Queue("fanout_queue_email"),//指定队列
exchange = @Exchange(value = "fanout_exchange",type ="fanout" )//指定交换机和类型
))
public void subConsumerEmail(Message message) { //Massage对象用来接收,也可以用Object,User
byte[] body = message.getBody();
String msg = new String(body);
System.out.println("邮件到的消息 = " + msg);
}
@RabbitListener(bindings = @QueueBinding(
value =@Queue("fanout_queue_sms"),//指定队列
exchange = @Exchange(value = "fanout_exchange",type ="fanout" )//指定交换机和类型
))
public void subConsumerSms(Message message) { //Massage对象用来接收,也可以用Object,User
byte[] body = message.getBody();
String msg = new String(body);
System.out.println("短信到的消息 = " + msg);
}
}
使⽤
@RabbitListener
注解及其相关属性定制了两个消息组件的消费者,这两个消费者都接收实体类 User并消费。
在
@RabbitListener
注解中,
bindings
属性⽤于创建并绑定交换器和消息队列组件,需要注意是,
为了能使两个消息组件的消费者接收到实体类
User
,需要我们在定制交换器时将交换器类型
type
设置为
fanout
。
另 外,bindings
属性的
@QueueBinding
注解除了有
value
、
exchange
属性外,还有
key
属性⽤于定制路由键 routingKey(当前发布订阅模式不需要)。
二.路由模式
/** 2.1 路由模式消息接收,处理error级别⽇志信息 */
@RabbitListener(bindings = @QueueBinding(
value = @Queue("routing_queue_error"),
exchange = @Exchange(value = "routing_exchange", type = "direct"),
key = "error_routing_key"))
public void routingConsumerError(String message) {
System.out.println("接收到error级别⽇志消息:" + message);
}
/** 2.2 路由模式消息接收,处理info、error、warning级别⽇志信息 */
@RabbitListener(bindings = @QueueBinding(
value = @Queue("routing_queue_all"),
exchange = @Exchange(value = "routing_exchange", type = "direct"),
key = {"error_routing_key", "info_routing_key", "warning_routing_key"}))
public void routingConsumerAll(String message) {
System.out.println("接收到info、error、warning等级别⽇志消息:" + message);
}
三.Topics(主题模式)
/**
* 3.1 通配符模式消息接收,进⾏邮件业务订阅处理
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic_queue_email"),
exchange = @Exchange(value = "topic_exchange", type = "topic"),
key = "info.#.email.#"))
public void topicConsumerEmail(String message) {
System.out.println("接收到邮件订阅需求处理消息:" + message);
}
/**
* 3.2 通配符模式消息接收,进⾏短信业务订阅处理
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic_queue_sms"),
exchange = @Exchange(value = "topic_exchange", type = "topic"),
key = "info.#.sms.#"))
public void topicConsumerSms(String message) {
System.out.println("接收到短信订阅需求处理消息:" + message);
}
四消息确认机制实现
# 配置RabbitMQ消息中间件连接配置
spring:
rabbitmq:
host: 192.168.48.67
port: 5672
username: admin
password: 123456
virtual-host: /zhengchunbo # 配置RabbitMQ虚拟主机路径(默认为"/"可以省略)
# ACK消息确认
publisher-confirm-type: simple # 发送者开启confirm确认机制
publisher-returns: true # 发送者开启return确认机制
config
包下创建
PublisherConfirmAndReturnConfig
类,并实现
RabbitTemplate
提供的
ConfirmCallback
和
ReturnsCallback
接⼝。
package com.example.demo.collection.config;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* RabbitTemplate消息确认机制相关接⼝介绍:
* 1.ConfirmCallback接⼝实现消息发送到交换机(Exchange)的回调
* 2.ReturnsCallback接⼝实现消息发送到队列(Queue)的回调
*/
@Component
public class PublisherConfirmAndReturnConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void initMethod() {
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnsCallback(this);
}
/**
* @param correlationData 相关性数据。对象内⼜⼀个id属性,⽤来表示当前消息的唯⼀性
* @param ack 消息投递到broker的状态,true表示成功
* @param cause 表示投递失败的原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息发送到交换机成功");
} else {
System.out.println("消息发送到交换机失败");
}
}
/**
* 消息在往队列发送时,如果消息发送成功,则不会调⽤此回调⽅法,如果消息发送失败,则会调⽤此回调⽅
* 法。
*
* @param returnedMessage ReturnedMessage表示返回消息对象,该类中有5个属性,含义⻅下:
* message:发送的消息内容
* replyCode:回应码
* replyText:回应信息
* exchange:交换机
* routingKey:路由键
*/
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
System.out.println("消息发送到交换机但未分发到队列");
}
}
五消息限流机制实现
1.在resource资源⽂件夹⾥application.yml⽂件中添加消费者限流处理的配置。
spring :rabbitmq :listener :simple :acknowledge-mode : manual # 开启⼿动签收 ( ⼿动 ACK)prefetch : 3 # ⼀次接收 3 条消息 ( 在单个请求中处理的消息个数 )concurrency : 1 # 消费者最⼩数量max-concurrency : 10 # 消费者最⼤数量