@Configuration
@EnableRabbit
public class RabbitMqConfig {
public static final String CONFIRM_EXCHANGE_NAME = "confirm-exchange";
public static final String BACK_EXCHANGE_NAME = "back-confirm-exchange";
public static final String CONFIRM_QUEUE_NAME = "confirm-queue";
public static final String BACK_QUEUE_NAME = "back-confirm-queue";
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private Integer port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Bean(name="myRabbitTemplate")
//@Scope
public RabbitTemplate rabbitTemplate(){
RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory());
return template;
}
@Bean
public CachingConnectionFactory cachingConnectionFactory(){
//新建缓存连接工厂
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(host);
factory.setPassword(password);
factory.setUsername(username);
factory.setPort(port);
return factory;
}
//新建确认交换机
@Bean
public DirectExchange confirmExchange(){
return ExchangeBuilder.
directExchange(CONFIRM_EXCHANGE_NAME).
durable(true).
build();
}
//确认队列
@Bean
public Queue confirmQueue(){
return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
}
//绑定交换机和队列
@Bean
public Binding confirmBinding(){
return BindingBuilder.bind(confirmQueue()).to(confirmExchange()).with("ack");
}
}
@SpringBootTest
class SpringbootRabbitmqSend02ApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
rabbitTemplate.convertAndSend("confirm-exchange","ack","你好");
}
}
@Configuration
@EnableRabbit
public class RabbitMqConfig {
public static final String CONFIRM_EXCHANGE_NAME = "confirm-exchange";
public static final String BACK_EXCHANGE_NAME = "back-confirm-exchange";
public static final String CONFIRM_QUEUE_NAME = "confirm-queue";
public static final String BACK_QUEUE_NAME = "back-confirm-queue";
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private Integer port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Bean(name="myRabbitTemplate")
//@Scope
public RabbitTemplate rabbitTemplate(AckCallBack ackCallBack, ReturnCallBack returnCallBack){
RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory());
template.setConfirmCallback(ackCallBack);
template.setMandatory(true);//true交换机回退 false 直接丢弃
template.setReturnsCallback(returnCallBack);
return template;
}
@Bean
public CachingConnectionFactory cachingConnectionFactory(){
//新建缓存连接工厂
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(host);
factory.setPassword(password);
factory.setUsername(username);
factory.setPort(port);
factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
return factory;
}
//新建确认交换机
@Bean
public DirectExchange confirmExchange(){
return ExchangeBuilder.
directExchange(CONFIRM_EXCHANGE_NAME).
durable(true).
build();
}
//确认队列
@Bean
public Queue confirmQueue(){
return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
}
//绑定交换机和队列
@Bean
public Binding confirmBinding(){
return BindingBuilder.bind(confirmQueue()).to(confirmExchange()).with("ack");
}
}
@Component
@Slf4j
public class AckCallBack implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
String id = correlationData != null ?correlationData.getId():"";
if(ack){
log.info("交换机已经收到id:{}消息了",id);
}else{
log.info("交换机没有收到id:{}消息,原因是:{}",id,cause);
}
}
}
@Component
@Slf4j
public class ReturnCallBack implements RabbitTemplate.ReturnsCallback {
@Override
public void returnedMessage(ReturnedMessage returned) {
Message message = returned.getMessage();
log.info("消息:{}被服务器退回,退回原因:{},退回码:{}",
message.getBody(),
returned.getReplyText(),
returned.getReplyCode());
/**
* 处理方式
* 1:尝试重新调用
* 2:落库处理,存入 mysql 数据库中
*/
}
}
@Configuration
@EnableRabbit
public class RabbitMqConfig {
public static final String CONFIRM_EXCHANGE_NAME = "confirm-exchange";
public static final String BACK_EXCHANGE_NAME = "back-confirm-exchange";
public static final String CONFIRM_QUEUE_NAME = "confirm-queue";
public static final String BACK_QUEUE_NAME = "back-confirm-queue";
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private Integer port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Bean(name="myRabbitTemplate")
public RabbitTemplate rabbitTemplate(AckCallBack ackCallBack, ReturnCallBack returnCallBack){
RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory());
template.setConfirmCallback(ackCallBack);
template.setMandatory(true);//true交换机回退 false 直接丢弃
template.setReturnsCallback(returnCallBack);
return template;
}
@Bean
public CachingConnectionFactory cachingConnectionFactory(){
//新建缓存连接工厂
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(host);
factory.setPassword(password);
factory.setUsername(username);
factory.setPort(port);
factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
return factory;
}
//建立确认交换机
@Bean("confirmExchange")
public DirectExchange confirmExchange(){
return ExchangeBuilder.
directExchange(CONFIRM_EXCHANGE_NAME).
durable(true).
withArgument("alternate-exchange",BACK_EXCHANGE_NAME).
build();
}
//确认队列
@Bean
public Queue confirmQueue(){
return QueueBuilder.durable(CONFIRM_QUEUE_NAME).build();
}
//绑定交换机和队列
@Bean
public Binding confirmBinding(){
return BindingBuilder.bind(confirmQueue()).to(confirmExchange()).with("ack");
}
//声明备份交换机
@Bean("backExchange")
public FanoutExchange backExchange(){
return new FanoutExchange(BACK_EXCHANGE_NAME);
}
//声明备份队列
@Bean("backQueue")
public Queue backQueue(){
return QueueBuilder.durable(BACK_QUEUE_NAME).build();
}
//绑定备份交换机和队列
@Bean
public Binding backBinding(){
return BindingBuilder.bind(backQueue()).to(backExchange());
}
}
spring:
rabbitmq:
host: 192.168.245.129
port: 5672
username: wj
password: 123456
listener:
simple:
retry:
enabled: true
acknowledge-mode: manual #手动ack
@Service
@Slf4j
public class MessageReceive {
@RabbitListener(queues = {"back-confirm-queue"})
public void receive(String body, Channel channel, Message message) throws IOException {
try {
log.info("队列消息"+body);
int ret = 1/0;
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (Exception e) {
if (message.getMessageProperties().getRedelivered()){
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
}else {
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
}
}
}
}
消息满足刚提到的几个条件之后,消息进入死信队列
//确认队列
@Bean("confirmQueue")
public Queue confirmQueue() {
// return QueueBuilder.durable(TEST_QUEUE_NAME).build();
Map map = new HashMap<>();
//设置队列过期时间
// map.put("x-message-ttl",5000);
map.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
//设置队列最大长度
// map.put("x-max-length",10);
return QueueBuilder.durable(TEST_QUEUE_NAME).withArguments(map).build();
}
//确认队列
@Bean("confirmQueue")
public Queue confirmQueue() {
// return QueueBuilder.durable(TEST_QUEUE_NAME).build();
Map map = new HashMap<>();
//设置队列过期时间
// map.put("x-message-ttl",5000);
map.put("x-dead-letter-exchange",DEAD_EXCHANGE_NAME);
//设置队列最大长度
// map.put("x-max-length",10);
return QueueBuilder.durable(TEST_QUEUE_NAME).withArguments(map).build();
}
//拒收演示
@RabbitListener(queues = {"test-queue"})
public void receiveReject(String body, Channel channel, Message message) throws IOException {
try {
if ("3".equals(body)){
log.info("收到异常队列消息"+body);
int ret = 1/0;
}
log.info("队列消息"+body);
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (Exception e) {
if (message.getMessageProperties().getRedelivered()){
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
}else {
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
}
}
}
延时队列:消息进入队列后不会立即被消费,只有到达指定时间后,才会被消费,最重要的特征就是延迟上
RabbitMQ未提供延时队列功能,但是我们可以通过 TTL + 死信队列的方式设计出延时队列