图解
目标:
1. 生产者发送消息到RabbitMQ
2. 消费者从RabbitMQ获取消息
3. 消息过期时间TTL
4. 死信队列
5. 消息确认机制
代码结构
1、maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、application.yml
server:
port: 8080
spring:
rabbitmq:
username: admin
password: admin
virtual-host: /
host: 192.168.xxx.xxx
port: 5672
publisher-confirm-type: correlated #消息确认机制需要
3、生产者
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Configuration
public class DirectRabbitConfig {
//创建队列
@Bean
public Queue queue1() {
return new Queue("direct.query1.java", true);
}
@Bean
public Queue query2() {
return new Queue("direct.query2.java", true);
}
// 创建交换机
@Bean
public DirectExchange directExchange() {
return new DirectExchange("direct-exChange-java");
}
// 绑定交换机和队列
@Bean
public Binding bindingQuery1() {
return BindingBuilder.bind(queue1()).to(directExchange()).with("student");
}
@Bean
public Binding bindingQuery2() {
return BindingBuilder.bind(query2()).to(directExchange()).with("teacher");
}
}
模拟service层
import com.shao.springbootrabbitmqdirectproducer.config.MessageConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DirectRabbitServcice {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private MessageConfirmCallback messageConfirmCallback;
// 定义交换机
private final String exChange = "direct-exChange-java";
public void sendManage(int num, String routeKey) {
String massage = "这是第" + num + "条订单";
System.out.println(massage);
// 发送消息到RabbitMQ 注意:routeKey字段必须要写,不然消息发不到队列中
rabbitTemplate.convertAndSend(exChange, routeKey, massage);
}
}
4、消费者
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "direct.query1.java", autoDelete = "false"),
exchange = @Exchange(value = "direct-exChange-java",type = ExchangeTypes.DIRECT)
))
@Component
public class ConsumerOne {
//RabbitHandler 代表此方法为接受消息的方法,不要有返回值
@RabbitHandler
public void messageRevice(String message){
System.out.println("获取direct.query1.java中第"+message+"消息");
}
}
5、消息确认机制
添加类MessageConfirmCallback .java
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
@Component
public class MessageConfirmCallback implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if(b){
System.out.println("消息确认成功!!!!");
}else{
System.out.println("消息确认失败!!!!");
}
}
}
对 DirectRabbitServcice.java 进行修改
@Autowired
private MessageConfirmCallback messageConfirmCallback;
public void sendManage(int num, String routeKey) {
String massage = "这是第" + num + "条订单";
System.out.println(massage);
// 设置消息确认机制
rabbitTemplate.setConfirmCallback(messageConfirmCallback);
// 发送消息到RabbitMQ 注意:routeKey字段必须要写,不然消息发不到队列中
rabbitTemplate.convertAndSend(exChange, routeKey, massage);
}
6、消息过期时间
有两种实现方式:给队列添加过期时间,给消息添加过期时间
1. 给队列添加过期时间
在生产者DirectRabbitConfig.java中添加一个队列,并绑定交换机
@Bean
public Queue query3() {
Map<String, Object> hashMap = new HashMap<String, Object>();
// 设置队列过期时间
hashMap.put("x-message-ttl",5000);
return new Queue("direct.query3.java", true,false,false,hashMap);
}
@Bean
public Binding bindingQuery3() {
return BindingBuilder.bind(query3()).to(directExchange()).with("ttl");
}
2. 给消息添加过期时间
对 DirectRabbitServcice.java 进行修改
public void sendManage(int num, String routeKey) {
String massage = "这是第" + num + "条订单";
System.out.println(massage);
// 给消息添加过期时间
MessagePostProcessor messagePostProcessor = new MessagePostProcessor(){
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setExpiration("5000");
message.getMessageProperties().setContentEncoding("UTF-8");
return message;
}
};
// 发送消息到RabbitMQ 注意:routeKey字段必须要写,不然消息发不到队列中
rabbitTemplate.convertAndSend(exChange, routeKey, massage,messagePostProcessor);
}
7、死信队列
当消息被拒绝、消息过期、队列达到最大长度时消息将放到死信队列
在生产者DirectRabbitConfig.java中添加一个死信队列和死信交换机并进行绑定,代码中测试的是队列达到最大长度将消息放到死信队列
@Bean
public Queue query3() {
Map<String, Object> hashMap = new HashMap<String, Object>();
// 设置队列过期时间
//hashMap.put("x-message-ttl",5000);
// 设置长度,超过长度的消息放入死信队列
hashMap.put("x-max-length",6);
// 设置死信队列 direct模式需要设置x-dead-letter-routing-key
hashMap.put("x-dead-letter-exchange","direct-Dead-exChange-java");
hashMap.put("x-dead-letter-routing-key","dead");
return new Queue("direct.query3.java", true,false,false,hashMap);
}
// 设置死信队列
@Bean
public Queue query4() {
return new Queue("direct.quer4.java", true);
}
// 创建死信交换机
@Bean
public DirectExchange directDeadExchange() {
return new DirectExchange("direct-Dead-exChange-java");
}
@Bean
public Binding bindingQuery3() {
return BindingBuilder.bind(query3()).to(directExchange()).with("ttl");
}
@Bean
public Binding bindingQuery4() {
return BindingBuilder.bind(query4()).to(directDeadExchange()).with("dead");
}