Springboot整合RabbitMQ和基本操作
引入RabbitMQ依赖
需要在pox.xml中引入RabbitMQ的相关依赖包
<!-- rabbitmq依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.3.9.RELEASE</version>
</dependency>
配置RabbitMQ信息
在application.properties文件中添加RabbitMQ的相关配置项,
包括RabbitMQ服务器host、端口号、用户名和密码等信息。
## rabbitmq相关配置
spring.rabbitmq.virtual-host=/
# RabbitMQ服务器地址
spring.rabbitmq.host=localhost
# RabbitMQ服务器端口号
spring.rabbitmq.port=5672
# RabbitMQ用户名
spring.rabbitmq.username=guest
# RabbitMQ密码
spring.rabbitmq.password=guest
配置RabbitMQ相关Bean
为了更方便使用RabbitMQ的相关操作组件,可在项目中自定注入和配置Bean相关组件,
/**
* RabbitMQ相关配置类
* @author huangqiqin
* @date 2021/04/13 00:31
**/
@Configuration
public class RabbitmqConfig {
private static final Logger log = LoggerFactory.getLogger(RabbitmqConfig.class);
/**
* 注入 RabbitMQ 的链接工厂
*/
@Autowired
private CachingConnectionFactory connectionFactory;
/**
* 注入 RabbitMQ 消息监听器所在的容器工厂配置类
*/
@Autowired
private SimpleRabbitListenerContainerFactoryConfigurer containerFactoryConfigurer;
/**
* 创建单个消息者实例下的消息监听器的容器工厂
* @return
*/
@Bean(name = "singleListenerContainer")
public SimpleRabbitListenerContainerFactory singleListenerContainerFactory(){
// 创建消息监听器所有容器工厂
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
// 设置容器工厂所使用的容器
factory.setConnectionFactory(connectionFactory);
// 设置消息传输的格式(这里采用JSON格式)
//factory.setMessageConverter(new Jackson2JsonMessageConverter());
// 设置并发消费者实例的初始数量
factory.setConcurrentConsumers(1);
// 设置并发消费者实例的最大数量
factory.setMaxConcurrentConsumers(1);
// 设置并发消费者实例中每个实例拉取的消息数量
factory.setPrefetchCount(1);
return factory;
}
/**
* 创建多个消息者实例下的消息监听器的容器工厂,主要针对高并发业务场景
* @return
*/
@Bean(name = "multiListenerContainer")
public SimpleRabbitListenerContainerFactory multiListenerContainerFactory(){
// 创建消息监听器所有容器工厂
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
// 设置容器工厂所使用的容器
factory.setConnectionFactory(connectionFactory);
// 设置消息传输的格式(这里采用JSON格式)
factory.setMessageConverter(new Jackson2JsonMessageConverter());
// 设置并发消费者实例的初始数量
factory.setConcurrentConsumers(10);
// 设置并发消费者实例的最大数量
factory.setMaxConcurrentConsumers(15);
// 设置并发消费者实例中每个实例拉取的消息数量
factory.setPrefetchCount(10);
// 设置消息的确认消费模式。这里设置为NONE,表示不需要确认(MANUAL手动确认,AUTO自动确认)
factory.setAcknowledgeMode(AcknowledgeMode.NONE);
return factory;
}
/**
* 配置RabbitMQ发送消息模板
* @return
*/
@Bean
public RabbitTemplate rabbitTemplate(){
// 设置发送消息后进行确认
connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
// 设置发送消息返回确认消息
connectionFactory.setPublisherReturns(true);
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
// 设置消息发送成功后的回调
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
log.info("==> 消息发送到RabbitMQ是否成功:{},失败原因:{}。", ack, cause);
}
});
// 设置消息发送失败后的回调
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int replayCode, String replayText,
String exchange, String routingKey) {
log.error("==> 消息发送失败:replayCode={}, replayText={}, exchange={}, routingKey={}",
replayCode, replayText, exchange, routingKey);
}
});
return rabbitTemplate;
}
}
发送和接收基本类型消息
创建队列、交换机、路由和绑定
/**
* 基本类型消息的队列、交换机、路由、绑定等对象配置类
* @author huangqiqin
* @date 2021/04/13 01:08
**/
@Configuration
public class BasicMessageConfig {
/**
* 注入配置文件的环境变量实例
*/
@Autowired
private Environment env;
/**
* 创建队列
* @return
*/
@Bean(name = "basicQueue")
public Queue basicQueue(){
return new Queue(env.getProperty("mq.basic.queue.name"), true);
}
/**
* 创建交换机:可持久化数据的交换机
* @return
*/
@Bean
public DirectExchange basicExchange(){
return new DirectExchange(env.getProperty("mq.basic.exchange.name"), true, false);
}
/**
* 创建绑定:将上面创建的队列绑定到交换机上,并设置路由key
* @return
*/
@Bean
public Binding basicBinding(){
return BindingBuilder
.bind(basicQueue())
.to(basicExchange())
.with(env.getProperty("mq.basic.routing.key.name"));
}
}
其中环境变量env中配置(application.properties)信息如下:
# 基本类型消息的队列名称
mq.basic.queue.name=basic.queue
# 交换机名称
mq.basic.exchange.name=basic.exchange
# 路由key
mq.basic.routing.key.name=basic.routing.key
创建消息发送者类
/**
* 基本类型消息的发送器
* @author huangqiqin
* @date 2021/04/13 01:22
**/
@Component
public class BasicMessagePublisher {
private static final Logger log = LoggerFactory.getLogger(BasicMessagePublisher.class);
/**
* 注入JSON序列化对象
*/
@Autowired
private ObjectMapper objectMapper;
/**
* 注入RabbitMQ模板对象
*/
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 注入properties配置文件变量
*/
@Autowired
private Environment env;
/**
* 发送消息到RabbitMQ
* @param message
*/
public void sendMessage(String message){
try {
if (!StringUtils.isEmpty(message)){
// 设置消息传输格式为Json
//this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter(objectMapper));
// 指定消息发送的交换机
this.rabbitTemplate.setExchange(env.getProperty("mq.basic.exchange.name"));
// 指定消息发送的路由key
this.rabbitTemplate.setRoutingKey(env.getProperty("mq.basic.routing.key.name"));
// 将字符串转为Message对象
Message msg = MessageBuilder.withBody(message.getBytes("utf-8")).build();
// 转换消息格式并发送
//this.rabbitTemplate.convertAndSend(msg);
this.rabbitTemplate.send(msg);
log.info("==> 已发送消息到RabbitMQ,消息内容:{}", msg);
}
} catch (Exception e){
log.error("发送消息到RabbitMQ失败", e);
}
}
}
创建消息消费者
/**
* 基本类型消息的消费者
* @author huangqiqin
* @date 2021/04/14 00:37
**/
@Component
public class BasicMessageConsumer {
private static final Logger log = LoggerFactory.getLogger(BasicMessageConsumer.class);
/**
* 监听并接收消息队列中的消息,这里采用单一容器工厂实例
* @param message
*/
@RabbitListener(queues = "${mq.basic.queue.name}", containerFactory = "singleListenerContainer")
public void consumeMessage(@Payload String message){
try {
System.out.println("==> 接收到RabbitMQ消息:" + message);
} catch (Exception e){
log.error("==> 接收RabbitMQ队列中消息异常", e);
}
}
}
单元测试
运行单元测试时,由于消息生产者发送完消息到RabbitMQ之后,JVM便结束了,
此时消息者可能还没来得及消息呢,所以可能导致看不到有消息者消费消息的输出,
解决办法就是,先正常启动当前springboot应用,然后再运行当前测试单元即可。
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class BasicPublisherTest{
@Autowired
private BasicMessagePublisher publisher;
/**
* 测试发送基本类型消息到 RabbitMQ中
*/
@Test
public void sendMessage() {
String msg = "哈哈哈,这条消息是通过程序发送到RabbitMQ中的!!!!";
publisher.sendMessage(msg);
}
}
发送和接收对象类型消息
创建队列、交换机、路由和绑定
/**
* 对象类型消息的队列、交换机、路由、绑定等对象配置类
* @author huangqiqin
* @date 2021/04/16 22:00
**/
@Configuration
public class ObjectMessageConfig {
/**
* 注入配置文件的环境变量实例
*/
@Autowired
private Environment env;
/**
* 创建队列:可持久化的队列
* @return
*/
@Bean(name = "objectQueue")
public Queue objectQueue(){
return new Queue(env.getProperty("mq.object.queue.name"), true);
}
/**
* 创建交换机:可持久化数据的交换机
* @return
*/
@Bean(name = "objectExchange")
public DirectExchange objectExchange(){
return new DirectExchange(env.getProperty("mq.object.exchange.name"), true, false);
}
/**
* 创建绑定:将队列绑定到交换机上,并指定路由key
* @param objectQueue 注入上面创建的队列
* @param objectExchange 注入上面创建的交换机
* @return
*/
@Autowired
@Bean(name = "objectBinding")
public Binding objectBinding(Queue objectQueue, DirectExchange objectExchange){
return BindingBuilder
.bind(objectQueue) // 绑定objectQueue队列
.to(objectExchange) // 到objectExchange交换机上
.with(env.getProperty("mq.object.routing.key.name")); //指定路由key
}
}
其中环境变量env中配置(application.properties)信息如下:
# 对象类型消息的队列名称
mq.object.queue.name=object.queue
# 交换机名称
mq.object.exchange.name=object.exchange
# 路由key
mq.object.routing.key.name=object.routing.key
创建消息消费者
/**
* 对象类型消息的消费者
* @author huangqiqin
* @date 2021/04/16 22:13
**/
@Component
public class ObjectMessageConsumer {
/**
* 监听并接收消息队列中的消息,这里采用多消息容器工厂实例
* @param person
*/
@RabbitListener(queues = "${mq.object.queue.name}", containerFactory = "multiListenerContainer")
public void consumeMessage(@Payload Person person){
System.out.println("==> 接收到RabbitMQ消息:" + person);
}
}
创建消息发送者
/**
* 对象类型消息发送者
* @author huangqiqin
* @date 2021/04/16 22:32
**/
@Component
public class ObjectMessagePublisher {
/**
* 注入配置文件变量对象
*/
@Autowired
private Environment env;
/**
* 注入Rabbit模板
*/
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送对象消息
* @param person
*/
public void sendObjectMessage(Person person){
try {
if (person != null){
// 设置消息传输格式(Json)
this.rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
// 指定发送消息到对应的交换机
this.rabbitTemplate.setExchange(env.getProperty("mq.object.exchange.name"));
// 指定发送消息时对应的路由key
this.rabbitTemplate.setRoutingKey(env.getProperty("mq.object.routing.key.name"));
// 转换格式并发送消息,并重写消息发送后置处理器
this.rabbitTemplate.convertAndSend(person, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
// 获取消息属性
MessageProperties messageProperties = message.getMessageProperties();
// 设置消息持久化模式
messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
// 设置消息类型(这里需要指定消息类型为Person类型,否则消费者无法直接接收Person对象消息)
messageProperties.setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
Person.class
);
return message;
}
});
}
} catch (Exception e){
e.printStackTrace();
}
}
}
单元测试
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class ObjectMessagePublisherTest {
@Autowired
private ObjectMessagePublisher publisher;
@Test
public void sendObjectMessage() {
Person person = new Person(1001, "张三丰", 109);
System.out.println("==> 发送对象消息:");
this.publisher.sendObjectMessage(person);
}
}
完整的示例代码:https://gitee.com/huangqiqin/middleware-study/tree/master/rabbitmq