一、整合RabbitMQ
创建微服务:
添加依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
配置文件:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
创建配置类:
DeadLetterMqConfig配置类:
/**
* 这是一个 Spring Boot 应用程序的 Java 配置类,用于配置 RabbitMQ 的死信队列(Dead Letter Queue)
*/
@Configuration
public class DeadLetterMqConfig {
// 交换机名称
public static final String exchange_dead = "exchange.dead";
// 路由键
public static final String routing_dead_1 = "routing.dead.1";
public static final String routing_dead_2 = "routing.dead.2";
// 队列名称
public static final String queue_dead_1 = "queue.dead.1";
public static final String queue_dead_2 = "queue.dead.2";
/**
* 其他队列可以在RabbitListener上面做绑定
* 用于创建交换机
* @return
*/
@Bean
public DirectExchange exchange() {
return new DirectExchange(exchange_dead, true, false, null);
}
/**
* 定义了一个队列 queue1(),并设置了它的属性
* @return
*/
@Bean
public Queue queue1() {
Map<String, Object> arguments = new HashMap<>();
// x-dead-letter-exchange 和 x-dead-letter-routing-key,用于指定死信队列的交换机和路由键
arguments.put("x-dead-letter-exchange", exchange_dead);
arguments.put("x-dead-letter-routing-key", routing_dead_2);
// 队列名称、是否持久化、是否是独占队列、是否自动删除
return new Queue(queue_dead_1, true, false, false, arguments);
}
/**
* 定义了一个 Binding Bean
* @return
*/
@Bean
public Binding binding() {
// 将 queue1() 和 exchange() 绑定在一起,使用了 routing_dead_1 路由键
return BindingBuilder.bind(queue1()).to(exchange()).with(routing_dead_1);
}
/**
* 定义了另一个队列 queue2()
* @return
*/
@Bean
public Queue queue2() {
// 只设置了队列名称和是否持久化
return new Queue(queue_dead_2, true, false, false, null);
}
/**
* 定义了一个死信绑定
* @return
*/
@Bean
public Binding deadBinding() {
// 将 queue2() 和 exchange() 绑定在一起,使用了 routing_dead_2 路由键
return BindingBuilder.bind(queue2()).to(exchange()).with(routing_dead_2);
}
}
MQConfig 配置类:
/**
* 定义了一个名为messageConverter的bean,
* 它是一个消息转换器,用于将消息对象转换为JSON格式的字符串或将JSON格式的字符串转换为消息对象。
* 这里使用了Jackson库提供的Jackson2JsonMessageConverter类来实现转换功能。
*/
@Configuration
public class MQConfig {
@Bean
public MessageConverter messageConverter(){
//json字符串转换器,用于将消息在JSON和Java对象之间进行转换
return new Jackson2JsonMessageConverter();
}
}
MQConfirm 配置类:
/**
* 该类实现了RabbitTemplate.ConfirmCallback和RabbitTemplate.ReturnCallback接口,
* 分别用于消息发送确认和投递确认的回调处理
*/
@Component
public class MQConfirm implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
@Autowired
RabbitTemplate rabbitTemplate;
/**
* @PostConstruct 表示该方法会在Bean初始化之后自动调用。
* 在该方法中,rabbitTemplate(RabbitMQ的模板类)的确认回调和返回回调都被设置为当前对象(this)。
*/
@PostConstruct
public void init(){
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
}
/**
* confirm()方法是发送确认回调方法,
* 当消息发送成功或失败时都会执行该方法,并传入相关的参数,
* 可以在方法中根据返回的ack参数判断消息是否发送成功。
* @param correlationData
* @param ack
* @param cause
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("发送确认,不管发送成功或者失败都会执行");
}
/**
* returnedMessage()方法是投递确认回调方法,
* 当消息投递失败时会执行该方法,并传入相关的参数,
* 可以在方法中处理投递失败的情况。
* @param message
* @param replyCode
* @param replyText
* @param exchange
* @param routingKey
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("投递确认,只有投递失败时才会回调");
}
}
service层:
public interface MqService {
void sendMessage(String exchange,String routing,Object o);
}
@Service
public class MqServiceImpl implements MqService {
@Autowired
RabbitTemplate rabbitTemplate;
/**
* 调用者只需要提供交换机、路由和消息即可实现消息的发送。
* @param exchange
* @param routing
* @param o
*/
@Override
public void sendMessage(String exchange, String routing, Object o) {
// 发送的消息(o)转换并发送到指定的交换机和路由上
rabbitTemplate.convertAndSend(exchange,routing,o);
}
}
在service-sms微服务中进行RabbitMQ操作:
添加依赖:
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>rabbit-mq</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
添加配置文件:
#spring
rabbitmq:
# 发送消息时确认类型为简单模式,即只确认消息是否已经到达交换机
publisher-confirm-type: simple
# 设置消息发送失败时,消息会被退回到生产者(publisher)那里,以便后续处理
publisher-returns: true
host: localhost
port: 5672
username: guest
password: guest
添加监听器:
SmsReceiver 消息监听器:
@Component
public class SmsReceiver {
@Autowired
SmsService smsService;
/**
* 该方法是一个RabbitMQ消息队列的消费者。
* 该方法监听名为"recharge.routing"的路由键。
* @param channel
* @param message
* @param smsDTO
* @throws IOException
*/
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange(value = "recharge.exchange",durable = "true"), // 声明交换机名称和持久化
key = {"recharge.routing"},
value = @Queue(value = "recharge.queue",durable = "true") // 声明队列名称和持久化
))
public void a(Channel channel, Message message, SmsDTO smsDTO) throws IOException {
byte[] body = message.getBody(); // 获取消息体
String jsonStr = new String(body); // 将消息体转成字符串格式
// int i = 1/0;
System.out.println(jsonStr);
System.out.println("消费监听");
// 发短信
smsService.sendRechargeMessage();
// 提交消息:手动确认消息已经被消费,并提交确认信号给RabbitMQ服务器
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
// 回滚消息:回滚或拒绝消息,放回队列等待重新消费
// channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
}
}
SmsDeadReceiver 监听器:
/**
* 它包含了两个方法a和b,
* 分别监听名为"queue.dead.1"和"queue.dead.2"的RabbitMQ队列。
* 当有消息进入队列时,这两个方法将被调用。
*/
@Component
public class SmsDeadReceiver {
/**
* 声明监听名为"queue.dead.1"的队列
* @param channel 用于与RabbitMQ通信
* @param message 表示收到的消息
* @param o 可选的,通常用于传递附加信息
* @throws IOException
*/
@RabbitListener(queues = "queue.dead.1")
public void a(Channel channel, Message message, Object o) throws IOException {
byte[] body = message.getBody(); // 获取消息的body
String jsonStr = new String(body); // 将body转换为String类型
// 回滚消息后进入死信队列:第二个表示是否重新投递,第三个表示是否将消息投递到当前消费者之前的所有消费者中
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
}
/**
* 声明监听名为"queue.dead.2"的队列
* @param channel 用于与RabbitMQ通信
* @param message 表示收到的消息
* @param o 可选的,通常用于传递附加信息
* @throws IOException
*/
@RabbitListener(queues = "queue.dead.2")
public void b(Channel channel, Message message, Object o) throws IOException {
byte[] body = message.getBody();
String jsonStr = new String(body);
// 回滚消息:第二个表示是否将确认应用于多个消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}