rabbitMq延迟消息队列
在实际的企业开发中,消息中间件是至关重要的组件之一。消息中间件主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。延迟队列是存储延迟消息的队列,延迟消息就是生产者发送了一条消息,但是不希望该消息不要被立即消费,而是设置一个延迟时间,等过了这个时间再消费消息。
1、新建立消息队列配置文件application.properties
#rabbit消息队列的配置
spring.cloud.stream.binders.work_proof.type=rabbit
spring.cloud.stream.binders.work_proof.environment.spring.rabbitmq.host=localhost
spring.cloud.stream.binders.work_proof.environment.spring.rabbitmq.port=5672
spring.cloud.stream.binders.work_proof.environment.spring.rabbitmq.username=user
spring.cloud.stream.binders.work_proof.environment.spring.rabbitmq.password=123456
#发布者
spring.cloud.stream.bindings.user_output.binder=hua_work_proof spring.cloud.stream.bindings.user_output.destination=envelope_stream spring.cloud.stream.bindings.user_output.consumer.maxAttempts=1 spring.cloud.stream.bindings.user_output.consumer.concurrency=5 spring.cloud.stream.bindings.user_output.producer.required-groups=envelope_input spring.cloud.stream.rabbit.bindings.user_output.producer.delayed-exchange=true //延迟队列的配置
#消费者 spring.cloud.stream.bindings.user_input.binder=hua_work_proof spring.cloud.stream.bindings.user_input.destination=envelope_stream spring.cloud.stream.bindings.user_input.group=envelope_input spring.cloud.stream.bindings.user_input.consumer.maxAttempts=1 spring.cloud.stream.rabbit.bindings.user_input.consumer.delayed-exchange=true //延迟队列的配置
注意这里的一个新参数 spring.cloud.stream.rabbit.bindings.user-output.producer.delayed-exchange,用来开启延迟消息的功能,这样在创建exchange的时候,会将其设置为具有延迟特性的exchange,也就是用到上面我们安装的延迟消息插件的功能。
2.1新建一个发布端接口
package com.alpha.product.service; import org.springframework.cloud.stream.annotation.Output; import org.springframework.messaging.MessageChannel; public interface StreamOutput { final String USER_OUTPUT ="user_output"; @Output(USER_OUTPUT ) MessageChannel userOutput(); }
2.2新建一个发布者
package com.alpha.product.service;
import java.time.Duration;
import java.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.support.MessageBuilder;
import com.alpha.frame.enhance.module.common.anno.service.CommonService;
@EnableBinding(StreamOutput.class) //绑定发布端
@CommonService
public class StreamOutputService {
private static final Logger log = LoggerFactory.getLogger(StreamOutputService.class);
@Autowired
private StreamOutput streamOutput;
public void send(Long userId,LocalDateTime endTime){
if(userId== null || endTime == null){
return;
}
LocalDateTime now = LocalDateTime.now();
long duration = Duration.between(now,endTime).toMillis();
log.warn("准备发送延迟消息队列 userId:{},now:{} endTime:{} Duration:{}",userId,now,endTime,duration);
streamOutput.envelopeOutput().send(MessageBuilder.withPayload(userId).setHeader("x-delay",duration).build());//延迟队列的发送方式
}
}
2.1新建一个消费端接口
package com.alpha.product.stream; import org.springframework.cloud.stream.annotation.Input; import org.springframework.messaging.SubscribableChannel; public interface StreamInput { final String USER_INPUT ="user_input"; @Input(USER_INPUT) SubscribableChannel userInput(); }
2.2新建一个消费者
package com.alpha.product.stream;
import java.time.LocalDateTime;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
@EnableBinding(StreamInput.class)//绑定消费端
@Component
public class StreamInputService {
private static final Logger log = LoggerFactory.getLogger(StreamInputService.class);
@StreamListener(StreamInput.USER_INPUT) //监听RabbitMq的消息
private void listener(Message<String> message) {
log.warn("now:{} 接受到一条消息队列 content:{}",LocalDateTime.now(),JSONObject.toJSONString(message));
if(message == null){
return;
}
try{
String payload = message.getPayload();
if(!NumberUtils.isParsable(payload)){
log.error("消息内容异常:payload:{}",payload);
return;
}
//业务操作
}catch(Exception e){
e.printStackTrace();
}
}
}
3,测试类
@RunWith(SpringRunner.class) @SpringBootTest(classes = {BrowserDevApplication.class}) public class TestDemo { //当前时间的明天
@Test
public void Test(){
outputService.send(sendRec.getUserId(),LocalDateTime.now().minusDays(-1));
}
}