【RabbitMQ】配置文件动态绑定交换机、队列、生产者、消费者
使用配置文件进行配置,然后代码动态产生队列,交换机,生产者,消费者,以及如果配置了死信队列则动态绑定死信队列。由此得出所有的这些都是根据配置进行操作。
配置
spring:
rabbitmq:
# 动态创建和绑定队列、交换机的配置
modules:
- routing-key: 路由KEY
producer: 生产者
consumer: 消费者
autoAck: 是否自动ACK
queue: 队列
name: 队列名称
dead-letter-exchange: 死信队列交换机
dead-letter-routing-key: 死信队列路由KEY
arguments: 队列其他参数,此配置支持RabbitMQ的扩展配置
# 1分钟(测试),单位毫秒
x-message-ttl: 3000 # 延迟队列
exchange: 交换机
name: 交换机名称
..... 省略其他配置
配置类实现
配置有了,接下来就是创建 Java 对象把配置对象化了,由于支持多个所以用的是集合接收配置。
package cn.com.codingce.utils.config;
import cn.com.codingce.utils.mq.ModuleProperties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* 绑定配置基础类
*
* @author ma
*/
@Data
@Configuration
@ConfigurationProperties("spring.rabbitmq")
public class RabbitModuleProperties {
/**
* 模块配置
*/
List<ModuleProperties> modules;
}
对应YML的配置类
package cn.com.codingce.utils.mq;
import lombok.Data;
import java.util.Map;
/**
* YML配置类
*
* @author ma
*/
@Data
public class ModuleProperties {
/**
* 路由Key
*/
private String routingKey;
/**
* 消费者
*/
private String consumer;
/**
* 生产者
*/
private String producer;
/**
* 新添加!!!!!
*/
private String retry;
/**
* 自动确认
*/
private Boolean autoAck = true;
/**
* 队列信息
*/
private Queue queue;
/**
* 交换机信息
*/
private Exchange exchange;
/**
* 交换机信息类
*/
@Data
public static class Exchange {
/**
* 交换机类型
* 默认主题交换机
*/
private RabbitExchangeTypeEnum type = RabbitExchangeTypeEnum.TOPIC;
/**
* 交换机名称
*/
private String name;
/**
* 是否持久化
* 默认true持久化,重启消息不会丢失
*/
private boolean durable = true;
/**
* 当所有队绑定列均不在使用时,是否自动删除交换机
* 默认false,不自动删除
*/
private boolean autoDelete = false;
/**
* 交换机其他参数
*/
private Map<String, Object> arguments;
}
/**
* 队列信息类
*/
@Data
public static class Queue {
/**
* 队列名称
*/
private String name;
/**
* 是否持久化
*/
private boolean durable = true; // 默认true持久化,重启消息不会丢失
/**
* 是否具有排他性
*/
private boolean exclusive = false; // 默认false,可多个消费者消费同一个队列
/**
* 当消费者均断开连接,是否自动删除队列
*/
private boolean autoDelete = false; // 默认false,不自动删除,避免消费者断开队列丢弃消息
/**
* 绑定死信队列的交换机名称
*/
private String deadLetterExchange;
/**
* 绑定死信队列的路由key
*/
private String deadLetterRoutingKey;
/**
* 交换机其他参数
*/
private Map<String, Object> arguments;
}
}
生产者&消费者,这里只需要定义个接口,后续会有实现类进行实现
生产者
package cn.com.codingce.utils.mq;
/**
* 生产者接口
*/
public interface ProducerService {
/**
* 发送消息
*
* @param message
*/
void send(Object message);
}
消费者
这里需要继承 RabbitMQ 的消费者接口,后续会直接把此接口给动态绑定到 RabbitMQ 中。
package cn.com.codingce.utils.mq;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
/**
* 消费者接口
*
* @author ma
*/
public interface ConsumerService extends ChannelAwareMessageListener {
}
重试处理器
package cn.com.codingce.utils.mq;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
/**
* 重试处理器
*
* @author ma
*/
public interface CustomRetryListener {
/**
* 最后一次重试失败回调
*
* @param context
* @param callback
* @param throwable
* @param <E>
* @param <T>
*/
<E extends Throwable, T> void lastRetry(RetryContext context, RetryCallback<T, E> callback, Throwable throwable);
/**
* 每次失败的回调
*
* @param context
* @param callback
* @param throwable
* @param <E>
* @param <T>
*/
<E extends Throwable, T> void onRetry(RetryContext context, RetryCallback<T, E> callback, Throwable throwable);
}
本次测试自定义重试。
package cn.com.codingce.utils.mq.retry;
import cn.com.codingce.utils.mq.CustomRetryListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.stereotype.Component;
/**
* HRA3报告
*
* @author ma
*/
@Component
@Slf4j
public class HraReportConsumerRetryListener implements CustomRetryListener {
@Override
public <E extends Throwable, T> void lastRetry(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.info("lastRetry 最后一次重试失败回调");
}
@Override
public <E extends Throwable, T> void onRetry(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.info("onRetry 每次失败的回调");
}
}
常量枚举定义
交换机类型枚举
package cn.com.codingce.utils.mq;
/**
* 交换机类型枚举
*
* @author ma
*/
public enum RabbitExchangeTypeEnum {
/**
* 直连交换机
* <p>
* 根据routing-key精准匹配队列(最常使用)
*/
DIRECT,
/**
* 主题交换机
* <p>
* 根据routing-key模糊匹配队列,*匹配任意一个字符,#匹配0个或多个字符
*/
TOPIC,
/**
* 扇形交换机
* <p>
* 直接分发给所有绑定的队列,忽略routing-key,用于广播消息
*/
FANOUT,
/**
* 头交换机
* <p>
* 类似直连交换机,不同于直连交换机的路由规则建立在头属性上而不是routing-key(使用较少)
*/
HEADERS;
}
队列,交换机,路由 常量枚举
package cn.com.codingce.utils.mq;
import lombok.Getter;
/**
* 队列,交换机。路由 常量枚举
*
* @author ma
*/
public enum RabbitEnum {
// QUEUE("BSH.{}.QUEUE", "队列名称"),
QUEUE("{}", "队列名称"),
// EXCHANGE("BSH.{}.EXCHANGE", "交换机名称"),
EXCHANGE("{}", "交换机名称"),
// ROUTER_KEY("BSH.{}.KEY", "路由名称"),
ROUTER_KEY("{}", "路由名称"),
;
RabbitEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
@Getter
private String value;
@Getter
private String desc;
}
核心代码
生产者实现类
其它生产者可继承此类,重写方法实现自己业务。
package cn.com.codingce.utils.mq;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Date;
/**
* 生产者实现类
*/
@Slf4j
public class AbsProducerService implements ProducerService {
@Resource
private RabbitTemplate rabbitTemplate;
/**
* 交换机
*/
private String exchange;
/**
* 路由
*/
private String routingKey;
/**
* 调整异步发送
*
* @param msg
*/
@Override
public void send(Object msg) {
MessagePostProcessor messagePostProcessor = (message) -> {
MessageProperties messageProperties = message.getMessageProperties();
messageProperties.setMessageId(IdUtil.randomUUID());
messageProperties.setTimestamp(new Date());
return message;
};
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentEncoding("UTF-8");
messageProperties.setContentType("text/plain");
String data = JSONUtil.toJsonStr(msg);
Message message = new Message(data.getBytes(StandardCharsets.UTF_8), messageProperties);
rabbitTemplate.convertAndSend(this.exchange, this.routingKey, message, messagePostProcessor);
}
public void setExchange(String exchange) {
this.exchange = exchange;
}
public void setRoutingKey(String routingKey) {
this.routingKey = routingKey;
}
}
消息监听工厂类实现
此实现非常重要,此处的代码就是绑定消费者的核心代码
package cn.com.codingce.utils.mq;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import java.util.Objects;
/**
* MQ具体消息监听器工厂
*
* @author ma
*/
@Data
@Slf4j
@Builder
public class ConsumerContainerFactory implements FactoryBean<SimpleMessageListenerContainer> {
/**
* MQ连接工厂
*/
private ConnectionFactory connectionFactory;
/**
* 操作MQ管理器
*/
private AmqpAdmin amqpAdmin;
/**
* 队列
*/
private Queue queue;
/**
* 交换机
*/
private Exchange exchange;
/**
* 消费者
*/
private ConsumerService consumer;
/**
* 重试回调
*/
private CustomRetryListener retryListener;
/**
* 最大重试次数
*/
private final Integer maxAttempts = 5;
/**
* 是否自动确认
*/
private Boolean autoAck;
@Override
public SimpleMessageListenerContainer getObject() throws Exception {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setAmqpAdmin(amqpAdmin);
container.setConnectionFactory(connectionFactory);
container.setQueues(queue);
container.setPrefetchCount(20);
container.setConcurrentConsumers(20);
container.setMaxConcurrentConsumers(100);
container.setDefaultRequeueRejected(Boolean.FALSE);
container.setAdviceChain(createRetry());
container.setAcknowledgeMode(autoAck ? AcknowledgeMode.AUTO : AcknowledgeMode.MANUAL);
if (Objects.nonNull(consumer)) {
container.setMessageListener(consumer);
}
return container;
}
/**
* 配置重试
*
* @return
*/
private Advice createRetry() {
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.registerListener(new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
// 第一次重试调用
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
if (Objects.nonNull(retryListener)) {
retryListener.onRetry(context, callback, throwable);
if (maxAttempts.equals(context.getRetryCount())) {
retryListener.lastRetry(context, callback, throwable);
}
}
}
});
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(maxAttempts));
retryTemplate.setBackOffPolicy(genExponentialBackOffPolicy());
return RetryInterceptorBuilder.stateless()
.retryOperations(retryTemplate).recoverer(new RejectAndDontRequeueRecoverer()).build();
}
/**
* 设置过期时间
*
* @return
*/
private BackOffPolicy genExponentialBackOffPolicy() {
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
// 重试间隔基数(秒)
backOffPolicy.setInitialInterval(5000);
// 从重试的第一次至最后一次,最大时间间隔(秒)
backOffPolicy.setMaxInterval(86400000);
// 重试指数
backOffPolicy.setMultiplier(1);
return backOffPolicy;
}
@Override
public Class<?> getObjectType() {
return SimpleMessageListenerContainer.class;
}
}
核心配置类
package cn.com.codingce.utils.config;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import cn.com.codingce.utils.mq.AbsProducerService;
import cn.com.codingce.utils.mq.ConsumerContainerFactory;
import cn.com.codingce.utils.mq.ConsumerService;
import cn.com.codingce.utils.mq.CustomRetryListener;
import cn.com.codingce.utils.mq.ModuleProperties;
import cn.com.codingce.utils.mq.RabbitEnum;
import cn.com.codingce.utils.mq.RabbitExchangeTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AbstractExchange;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* RabbitMQ 全局配置,SpringBoot 启动后会回调此类
*/
@Slf4j
@Configuration
public class RabbitMqConfig implements SmartInitializingSingleton {
/**
* MQ链接工厂
*/
private final ConnectionFactory connectionFactory;
/**
* MQ操作管理器
*/
private final AmqpAdmin amqpAdmin;
/**
* YML配置
*/
private final RabbitModuleProperties rabbitModuleProperties;
///////////////////////////////////////////////////////////////////////////
public static final String HEALTH_EXCHANGE = "EX_CHANGE";
public static final String HEALTH_RISK_EVAL_REPT = "HEALTH_RISK_EVAL_REPT";
public static final String CQZT_HRA3_ROUT_KEY = "cqzt.hra3.#";
public static final String CQZT_PSY_ROUT_KEY = "cqzt.psyReport.#";
public static final String CQZT_INTERVENTION_PROGRAM_ROUT_KEY = "cqzt.interventionProgram.#";
public static final String HEALTH_MONITOR_ROUT_KEY = "health.monitor.#";
/**
* 危急值
*/
public static final String HEALTH_MONITOR = "QUEUE_TO_HEALTH_MONITOR";
/**
* 干预方案队列
*/
public static final String HEALTH_INTERVENE_PROGRAM = "HEALTH_INTERVENE_PROGRAM";
/**
* 队列 个人心里报告
*/
public static final String HEALTH_PSY_REPT = "HEALTH_PSY_REPT";
///////////////////////////////////////////////////////////////////////////
@Autowired
public RabbitMqConfig(AmqpAdmin amqpAdmin, RabbitModuleProperties rabbitModuleProperties, ConnectionFactory connectionFactory) {
this.amqpAdmin = amqpAdmin;
this.rabbitModuleProperties = rabbitModuleProperties;
this.connectionFactory = connectionFactory;
}
@Override
public void afterSingletonsInstantiated() {
StopWatch stopWatch = StopWatch.create("MQ");
stopWatch.start();
log.debug("afterSingletonsInstantiated 初始化MQ配置");
List<ModuleProperties> modules = rabbitModuleProperties.getModules();
if (CollUtil.isEmpty(modules)) {
log.warn("afterSingletonsInstantiated 未配置MQ");
return;
}
for (ModuleProperties module : modules) {
try {
Queue queue = genQueue(module);
Exchange exchange = genQueueExchange(module);
// 绑定交换机
queueBindExchange(queue, exchange, module);
// 绑定生产者
bindProducer(module);
// 绑定消费者
bindConsumer(queue, exchange, module);
} catch (Exception e) {
log.error("afterSingletonsInstantiated 初始化失败", e);
}
}
stopWatch.stop();
log.info("afterSingletonsInstantiated 初始化MQ配置成功耗时: {}ms", stopWatch.getTotal(TimeUnit.MILLISECONDS));
}
/**
* 绑定生产者
*
* @param module
*/
private void bindProducer(ModuleProperties module) {
try {
log.info("bindProducer module:{}", JSON.toJSONString(module));
AbsProducerService producerService = SpringUtil.getBean(module.getProducer());
if (producerService != null) {
producerService.setExchange(module.getExchange().getName());
producerService.setRoutingKey(module.getRoutingKey());
log.debug("bindProducer 绑定生产者: {}", module.getProducer());
} else {
log.debug("bindProducer 未绑定生产者");
}
} catch (Exception e) {
log.warn("bindProducer 无法在容器中找到该生产者[{}],若需要此生产者则需要做具体实现", module.getConsumer());
}
log.debug("bindProducer 绑定生产者END -----------------------------------------------------------------");
}
/**
* 绑定消费者
*
* @param queue
* @param exchange
* @param module
*/
private void bindConsumer(Queue queue, Exchange exchange, ModuleProperties module) {
if (StrUtil.isNotBlank(module.getConsumer())) {
ConsumerService consumer = SpringUtil.getBean(module.getConsumer());
if (consumer != null) {
CustomRetryListener customRetryListener = null;
try {
if (StrUtil.isNotBlank(module.getRetry())) {
customRetryListener = SpringUtil.getBean(module.getRetry());
}
} catch (Exception e) {
log.debug("bindConsumer 无法在容器中找到该重试类[{}],若需要重试则需要做具体实现", module.getRetry());
}
try {
ConsumerContainerFactory factory = ConsumerContainerFactory.builder()
.connectionFactory(connectionFactory)
.queue(queue)
.exchange(exchange)
.consumer(consumer)
.autoAck(module.getAutoAck())
.amqpAdmin(amqpAdmin)
.build();
// 单独赋值
if (customRetryListener != null) {
log.debug("bindConsumer consumerContainerFactory setRetryListener done");
factory.setRetryListener(customRetryListener);
}
SimpleMessageListenerContainer container = factory.getObject();
if (Objects.nonNull(container)) {
container.start();
}
log.debug("bindConsumer 绑定消费者: {}", module.getConsumer());
} catch (Exception e) {
log.warn("bindConsumer 无法在容器中找到该消费者[{}],若需要此消费者则需要做具体实现", module.getConsumer());
}
} else {
log.debug("bindProducer 未绑定消费者");
}
} else {
log.debug("bindProducer 未绑定消费者");
}
log.debug("bindConsumer 绑定消费者END -----------------------------------------------------------------");
}
/**
* 队列绑定交换机
*
* @param queue
* @param exchange
* @param module
*/
private void queueBindExchange(Queue queue, Exchange exchange, ModuleProperties module) {
log.debug("queueBindExchange 初始化交换机: {}", module.getExchange().getName());
String queueName = module.getQueue().getName();
String exchangeName = module.getExchange().getName();
module.setRoutingKey(StrUtil.format(RabbitEnum.ROUTER_KEY.getValue(), module.getRoutingKey()));
String routingKey = module.getRoutingKey();
Binding binding = new Binding(queueName,
Binding.DestinationType.QUEUE,
exchangeName,
routingKey,
null);
amqpAdmin.declareQueue(queue);
amqpAdmin.declareExchange(exchange);
amqpAdmin.declareBinding(binding);
log.debug("queueBindExchange 队列绑定交换机: 队列: {}, 交换机: {}", queueName, exchangeName);
log.debug("queueBindExchange 队列绑定交换机END -----------------------------------------------------------------");
}
/**
* 创建交换机
*
* @param module
* @return
*/
private Exchange genQueueExchange(ModuleProperties module) {
ModuleProperties.Exchange exchange = module.getExchange();
RabbitExchangeTypeEnum exchangeType = exchange.getType();
exchange.setName(StrUtil.format(RabbitEnum.EXCHANGE.getValue(), exchange.getName()));
String exchangeName = exchange.getName();
Boolean isDurable = exchange.isDurable();
Boolean isAutoDelete = exchange.isAutoDelete();
Map<String, Object> arguments = exchange.getArguments();
return getExchangeByType(exchangeType, exchangeName, isDurable, isAutoDelete, arguments);
}
/**
* 根据类型生成交换机
*
* @param exchangeType
* @param exchangeName
* @param isDurable
* @param isAutoDelete
* @param arguments
* @return
*/
private Exchange getExchangeByType(RabbitExchangeTypeEnum exchangeType, String exchangeName, Boolean isDurable, Boolean isAutoDelete, Map<String, Object> arguments) {
AbstractExchange exchange = null;
switch (exchangeType) {
// 直连交换机
case DIRECT:
exchange = new DirectExchange(exchangeName, isDurable, isAutoDelete, arguments);
break;
// 主题交换机
case TOPIC:
exchange = new TopicExchange(exchangeName, isDurable, isAutoDelete, arguments);
break;
//扇形交换机
case FANOUT:
exchange = new FanoutExchange(exchangeName, isDurable, isAutoDelete, arguments);
break;
// 头交换机
case HEADERS:
exchange = new HeadersExchange(exchangeName, isDurable, isAutoDelete, arguments);
break;
default:
log.warn("getExchangeByType 未匹配到交换机类型");
break;
}
return exchange;
}
/**
* 创建队列
*
* @param module
* @return
*/
private Queue genQueue(ModuleProperties module) {
ModuleProperties.Queue queue = module.getQueue();
queue.setName(StrUtil.format(RabbitEnum.QUEUE.getValue(), queue.getName()));
log.debug("genQueue 初始化队列: {}", queue.getName());
Map<String, Object> arguments = queue.getArguments();
if (MapUtil.isEmpty(arguments)) {
arguments = new HashMap<>();
}
// 转换ttl的类型为long
if (arguments.containsKey("x-message-ttl")) {
arguments.put("x-message-ttl", Convert.toLong(arguments.get("x-message-ttl")));
}
// 绑定死信队列
String deadLetterExchange = queue.getDeadLetterExchange();
String deadLetterRoutingKey = queue.getDeadLetterRoutingKey();
if (StrUtil.isNotBlank(deadLetterExchange) && StrUtil.isNotBlank(deadLetterRoutingKey)) {
deadLetterExchange = StrUtil.format(RabbitEnum.EXCHANGE.getValue(), deadLetterExchange);
deadLetterRoutingKey = StrUtil.format(RabbitEnum.ROUTER_KEY.getValue(), deadLetterRoutingKey);
arguments.put("x-dead-letter-exchange", deadLetterExchange);
arguments.put("x-dead-letter-routing-key", deadLetterRoutingKey);
log.debug("genQueue 绑定死信队列: 交换机: {}, 路由: {}", deadLetterExchange, deadLetterRoutingKey);
}
return new Queue(queue.getName(), queue.isDurable(), queue.isExclusive(), queue.isAutoDelete(), arguments);
}
}
以上配置完成后,开始RUN代码。
使用示例
这里配置了延迟队列和死信队列,开RUN。
spring:
rabbitmq:
# 动态创建和绑定队列、交换机的配置
modules:
# 正常队列
- routing-key: health.hra3.#
producer: hraReportProducerService
consumer: hraReportConsumerService
autoAck: false
retry: hraReportConsumerRetryListener
queue:
name: HEALTH_RISK_EVAL_REPT
exchange:
name: EX_CHANGE
# 死信队列
- routing-key: dead
#consumer: deadConsumerService
#producer: deadProducerService
autoAck: false
queue:
name: DEAD_TEST
exchange:
name: DEAD_EXCHANGE
项目启动部分日志如下
: afterSingletonsInstantiated 初始化MQ配置
: genQueue 初始化队列: HEALTH_RISK_EVAL_REPT
: queueBindExchange 初始化交换机: EX_CHANGE
: queueBindExchange 队列绑定交换机: 队列: HEALTH_RISK_EVAL_REPT, 交换机: EX_CHANGE
: queueBindExchange 队列绑定交换机END -----------------------------------------------------------------
: bindProducer module:{"autoAck":false,"consumer":"hraReportConsumerService","exchange":{"autoDelete":false,"durable":true,"name":"EX_CHANGE","type":"TOPIC"},"producer":"hraReportProducerService","queue":{"autoDelete":false,"durable":true,"exclusive":false,"name":"HEALTH_RISK_EVAL_REPT"},"retry":"hraReportConsumerRetryListener","routingKey":"health.hra3.#"}
: bindProducer 绑定生产者: hraReportProducerService
: bindProducer 绑定生产者END -----------------------------------------------------------------
: bindConsumer consumerContainerFactory setRetryListener done
: bindConsumer 绑定消费者: hraReportConsumerService
: bindConsumer 绑定消费者END -----------------------------------------------------------------
: genQueue 初始化队列: DEAD_TEST
: queueBindExchange 初始化交换机: DEAD_EXCHANGE
: queueBindExchange 队列绑定交换机: 队列: DEAD_TEST, 交换机: DEAD_EXCHANGE
: queueBindExchange 队列绑定交换机END -----------------------------------------------------------------
: bindProducer module:{"autoAck":false,"exchange":{"autoDelete":false,"durable":true,"name":"DEAD_EXCHANGE","type":"TOPIC"},"queue":{"autoDelete":false,"durable":true,"exclusive":false,"name":"DEAD_TEST"},"routingKey":"dead"}
: bindProducer 无法在容器中找到该生产者[null],若需要此生产者则需要做具体实现
: bindProducer 绑定生产者END -----------------------------------------------------------------
: bindProducer 未绑定消费者
: bindConsumer 绑定消费者END -----------------------------------------------------------------
: afterSingletonsInstantiated 初始化MQ配置成功耗时: 114ms
交换机
队列
生产者发送消息
...
@Resource(name = "hraReportProducerService")
private HraReportProducerService hraReportProducerService;
...
hraReportProducerService.send(JSON.toJSONString(comMq));
消费者监听消息
package cn.com.codingce.utils.mq.consumer;
import com.alibaba.fastjson.JSON;
import cn.com.codingce.utils.mq.AbsConsumerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* HRA3报告
*
* @author ma
*/
@Component
@Slf4j
public class HraReportConsumerService extends AbsConsumerService {
@Override
public void onConsumer(Object data) throws IOException {
log.info("onConsumer data:{}", JSON.toJSONString(data));
ack();
}
}