简单记录Spring项目集成RabbitMQ的过程,重点记录生产者项目自动创建队列的操作,因该问题给项目带来很多麻烦。
本文内容分别在Spring(V5.2.6)和Spring Boot(V2.5.14)两个项目中经过了验证,下述示例代码来自于SpringBoot项目,迁移到Spring项目中需稍微调整。
Spring项目和SpringBoot项目的依赖有区别,按需引入:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbitartifactId>
<version>2.2.9.RELEASEversion>
dependency>
spring:
rabbitmq:
# 基础项
host: 192.168.1.123
port: 5672
username: admin
password: admin
# virtualhost需要提前在MQ的Web管理界面里手动创建,或者配置默认host"/"
virtual-host: /test
# 生产者
#确认消息已发送到交换机(Exchange)
publisher-confirm-type: correlated
#确认消息已发送到队列(Queue)
publisher-returns: true
# 消费者
listener:
type: simple
simple:
default-requeue-rejected: false
acknowledge-mode: auto #确认模式
prefetch: 1 #限制每次发送一条数据
max-concurrency: 1 #启动消费者最大数量
concurrency: 1 #同一个队列启动几个消费者
retry:
enabled: true #是否支持重试
说明:这里仅按照现有项目的配置列出,在实际的项目中,还是需要根据自身实际情况做出调整。
3.1 创建RabbitMQ配置类:
@Configuration
public class RabbitMQConfig {
//queue
public static final String WORK_QUEUE = "test.queue";
//exchange
public static final String WORK_DIRECTEXCHANGE = "test.directExchange";
//routing
public static final String WORK_DIRECTROUTING = "test.directRouting";
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
// Queue
@Bean
public Queue directQueue() {
Map<String, Object> argsMap = new HashMap<String, Object>();
argsMap.put("x-max-priority", 5);
Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap);
return queue;
}
//Direct交换机
@Bean
DirectExchange directExchange() {
return new DirectExchange(WORK_DIRECTEXCHANGE, true, false);
}
//绑定
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(directQueue()).to(directExchange()).with(WORK_DIRECTROUTING);
}
}
3.2 编写发送消息工具类:
@Component
public class RabbitMQUtils {
private static RabbitTemplate rabbitTemplate;
@Autowired
public RabbitMQUtils(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public static void sendMsg(String msg) throws AmqpException {
try {
rabbitTemplate.convertAndSend(RabbitMQConfig.WORK_DIRECTEXCHANGE, RabbitMQConfig.WORK_DIRECTROUTING, msg);
} catch (AmqpException e) {
throw new AmqpException ("RabbitMQ发送消息异常", e);
}
}
}
3.3 编写单元测试,测试发送消息结果。
4.1 编写监听器:
@Component
public class RabbitMQListener {
@RabbitListener(queues = {Constants.WORK_QUEUE})//监听队列
public void listener(String msg, Message message) {
System.out.println(msg);
System.out.println(message.getBody());
}
}
实际项目中,消息的生产者和消费者不在同一项目中,如果先启动消费者会因为没有队列而启动失败。
2.1 方式一:最容易想到的是,在MQ的Web管理界面中手动创建队列:
2.2 方式二:启动消费者项目时,监听器发现不存在队列自动创建:
2.3 方式三:先启动生产者项目:
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
@Bean
public Queue directQueue() {
Map<String, Object> argsMap = new HashMap<String, Object>();
argsMap.put("x-max-priority", 5);
Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap);
// 声明队列
rabbitAdmin.declareQueue(queue);
return queue;
}
@Configuration
public class RabbitMQConfig {
//queue
public static final String WORK_QUEUE = "test.queue";
//exchange
public static final String WORK_DIRECTEXCHANGE = "test.directExchange";
//routing
public static final String WORK_DIRECTROUTING = "test.directRouting";
@Autowired
private RabbitAdmin rabbitAdmin;
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
@Bean
public Queue directQueue() {
Map<String, Object> argsMap = new HashMap<String, Object>();
argsMap.put("x-max-priority", 5);
Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap);
rabbitAdmin.declareQueue(queue);
return queue;
}
//Direct交换机
@Bean
DirectExchange directExchange() {
return new DirectExchange(WORK_DIRECTEXCHANGE, true, false);
}
//绑定
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(directQueue()).to(directExchange()).with(WORK_DIRECTROUTING);
}
}