延迟任务通过消息的TTL和Dead Letter Exchange来实现。我们需要建立2个队列,一个用于发送消息,一个用于消息过期后的转发目标队列。
生产者输出消息到Queue1,并且这个消息是设置有有效时间的,比如60s。消息会在Queue1中等待60s,如果没有消费者收掉的话,它就是被转发到Queue2,Queue2有消费者,收到,处理延迟任务。
具体创建步骤如下:
1. 创建2个路由、2个队列:
路由:Exchange1、Exchange2。(均为普通路由)
队列:Queue1、Queue2。(Queue1为特殊队列,Queue2为普通队列)
Queue1需要设置 Dead letter exchange 参数(名称:x-dead-letter-exchange,值为刚才创建的Exchange2),当Queue1中的消息过期后,通过路由Exchange2转发。
2. 绑定
将Exchange1与Queue1绑定,Exchange2与Queue2绑定
1.引入jar包
org.springframework.boot
spring-boot-starter-amqp
2.创建路由、队列 (这部分在程序运行前手动执行,运行一次即可。也可以通过rabbit管理页面创建)
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 创建路由、队列,并绑定 (这个类不是Junit测试类,@Test标注的方法类似于main方法可直接运行)
*/
public class DlConfig {
final static String firstExchange = "firstExchange";
final static String firstQuque = "firstQuque";
final static String twoExchange = "twoExchange";
final static String twoQueue = "twoQueue";
final static String routingKey = "ddd";
/**
* 手动执行,创建路由、队列
*/
@Test
public void binding() throws IOException, TimeoutException{
//建立连接,创建通道
ConnectionFactory fc = new ConnectionFactory();
fc.setHost("localhost");
fc.setPort(5672);
fc.setUsername("guest");
fc.setPassword("guest");
Connection conn = fc.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDelete(firstExchange); //删除路由
channel.exchangeDelete(twoExchange);
channel.exchangeDeclare(firstExchange, BuiltinExchangeType.DIRECT); //创建路由
channel.exchangeDeclare(twoExchange, BuiltinExchangeType.DIRECT);
channel.queueDelete(firstQuque); //删除队列
Map map = new HashMap(); //设置队列参数
map.put("x-dead-letter-exchange", twoExchange);
channel.queueDeclare(firstQuque, true, false, false, map); //创建队列
channel.queueDelete(twoQueue);
channel.queueDeclare(twoQueue, true, false, false, null);
channel.queueBind(firstQuque, firstExchange, routingKey); //绑定路由、队列
channel.queueBind(twoQueue, twoExchange, routingKey);
channel.close();
conn.close();
}
}
3,消息发送者
import java.time.LocalDateTime;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 消息生产者
*/
@Component
public class DlProducer {
/** 引入rabbit的操作模板 */
@Autowired
RabbitTemplate rabbitTemplate;
/**
* 发送信息
*/
public void sender(){
MessagePostProcessor msg = new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message msg) throws AmqpException {
// 设置延迟毫秒值
msg.getMessageProperties().setExpiration("5000");
return msg;
}
};
rabbitTemplate.convertAndSend(DlConfig.firstExchange, DlConfig.routingKey, "哈哈哈哈哈"+LocalDateTime.now(), msg);
// 另一种写法 使用拉姆达表达式
rabbitTemplate.convertAndSend(DlConfig.firstExchange, DlConfig.routingKey, "哈哈哈哈哈"+LocalDateTime.now(), message -> {
// 设置延迟毫秒值
message.getMessageProperties().setExpiration(String.valueOf(5000));
return message;
});
}
}
4.消息接收者
import java.time.LocalDateTime;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 消息消费者
*/
@Component
public class DlConsumer {
/**
* 接收消息,监听 twoQueue 队列
*/
@RabbitListener(queues = "twoQueue")
public void ls(String message){
System.out.println(message+" | "+LocalDateTime.now());
}
}
运行结果:
哈哈哈哈哈2018-07-26T18:24:06.981 | 2018-07-26T18:24:11.993
哈哈哈哈哈2018-07-26T18:24:06.988 | 2018-07-26T18:24:11.995