开发过程中遇到的场景:需要spring boot整合rabbitMQ,并且对外提供rabbitMQ的服务,包括:rabbitMq的创建与配置、消息的发布publish,网上搜了很多都没找到这种场景相关的记录,整体过程记录如下:
- 国际惯例,添加依赖
- application.yml(property)配置
- rabbitConfig配置类
@Configuration
public class RabbitConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@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;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
@Bean
public ConnectionFactory connectionFactory(){
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(host);
factory.setPort(port);
factory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
factory.setPublisherReturns(true);
return factory;
}
@Bean
public RabbitTemplate rabbitTemplate(){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
//消息发送失败返回到队列中, yml需要配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
//消息返回确认是否到队列
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String correlationId = message.getMessageProperties().getCorrelationId();
logger.error("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {} 路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
});
//消息确认是否发送到exchange
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
if (correlationData != null) {
logger.info("消息发送到exchange成功,id: {}", correlationData.getId());
}
} else {
logger.error("消息发送到exchange失败,原因: {}", cause);
}
});
return rabbitTemplate;
}
}
- 消息发布逻辑
/**
* 发布消息,适用于direct、topic、fanout
* @param mqMessage 消息
* @return boolean
*/
@Override
public Boolean sendMsg(MqMessage mqMessage) {
logger.info("send queue msg: " + JSON.toJSONString(mqMessage));
try {
this.rabbitTemplate.convertAndSend(mqMessage.getExchangeName(), mqMessage.getRoutingKey(), mqMessage.getMsgContent(),
new CorrelationData(mqMessage.getMsgId()));
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
通过rabbitTemplate.convertAndsend进行消息发布。适用于direct(一对一)、topic(主题订阅)及fanout(广播)模式。direct及topic需要routingKey,fanout可以不需要。
- 模拟消息消费
/**
* TEST消息监听
* @param massage 消息
*/
@RabbitListener(bindings = {@QueueBinding(value = @Queue(value = "q1", durable = "true"),
exchange = @Exchange(value = "ex1", type = "topic"),
key = "t.message")})
public void processFanoutMsg(Message massage) {
String msg = new String(massage.getBody(), StandardCharsets.UTF_8);
logger.info("*************************** direct : {}", msg);
}
应用启动,就会收到logger.info消息。
- Mq创建配置服务
对外提供自定义创建exchange、queue、binding服务,通过AmqpAdmin实现。代码如下:
@Override
public Boolean createTopic(MqTopic mqTopic) {
logger.info("创建topicMq!");
logger.info("mqTopic为:{}", JSON.toJSONString(mqTopic));
String exchangeName = mqTopic.getExchangeName();
try {
amqpAdmin.declareExchange(new TopicExchange(exchangeName));
mqTopic.getMqInfos().forEach(e -> {
amqpAdmin.declareQueue(new Queue(e.getQueueName()));
amqpAdmin.declareBinding(new Binding(e.getQueueName(), Binding.DestinationType.QUEUE, exchangeName, e.getRoutingKey(), null));
});
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
AmqpAdmin:创建删除Queue、Exchange、Binding。declare开头的方法负责创建,delete开头的方法进行删除。
- 总结
简要记录整合过程,说明不算详细,欢迎大佬指正以便完善。