环境搭建
- 创建SpringBoot项目,选择Web模块中的Web依赖和RabbitMQ依赖及Integration依赖
- 编写配置文件,连接RabbitMQ服务 RabbitMQ介绍安装
- 如果没有在配置文件中配置外部RabbitMQ连接,会启用内部的RabbitMQ中间件,不推荐使用。
# 配置RabbitMQ消息中间件连接配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# 配置RabbitMQ虚拟主机路径/,默认可以省略
spring.rabbitmq.virtual-host=/
SpringBoot与RabbitMQ整合实现
- SpringBoot对RabbitMQ的工作模式进行了整合,并支持多种整合方式,包括基于API的方式、基于配置类的方式、基于注解的方式。
Public/Subscribe(发布订阅模式)
- 对于SpringBoot整合RabbitMQ中间件实现消息服务,通常包括三个工作:定制中间件、消息发送者发送消息、消息消费者接收消息。定义中间件比较麻烦,必须预先设定。
基于API方式
- 基于API方式主要是使用Spring框架提供的API管理类AmqpAdmin定制消息发送组件,并进行消息发送。
- 1)使用AmqpAdmin定制消息发送组件
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter08ApplicationTests {
@Autowired
private AmqpAdmin amqpAdmin;
@Test
public void amqpAdmin(){
// 定义fanout类型的交换器
amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange"));
// 定义两个默认持久化队列
amqpAdmin.declareQueue(new Queue("fanout_queue_email"));
amqpAdmin.declareQueue(new Queue("fanout_queue_sms"));
// 将队列分别与交换器进行绑定
amqpAdmin.declareBinding(new Binding("fanout_queue_email",Binding.DestinationType.QUEUE,
"fanout_exchange","",null));
amqpAdmin.declareBinding(new Binding("fanout_queue_sms",Binding.DestinationType.QUEUE,
"fanout_exchange","",null));
}
}
执行上述单元测试方法,可以在可视化管理页面localhost:15672中登录查看效果,出现了我们定义的fanout_exchange交换器,在Queues页面会有定制生成的消息队列信息。
- 2)消息发送者发送消息
- 完成消息组件的定制工作后,创建消息发送者发送消息到消息队列中。发送消息时,借助一个实体类User
public class User {
private Integer id;
private String username;
...
}
编写消息配置类,自定义Jackson2JsonMessageConverter类型的消息转换器组件
@Configuration
public class RabbitMQConfig {
@Bean
// 防止发送实体类消息时出现异常
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
编写测试方法
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void User(){
User user = new User();
user.setId(1);
user.setUsername("狗");
// 第一个参数表示发送消息的交换器,第二个参数表示路由键,对于Publish/Subscribe工作模式不需要指定,第三个参数为发送内容
rabbitTemplate.convertAndSend("fanout_exchange","",user);
}
效果测试: 执行方法后发现Queues消息队列中两个消息队列都拥有一条待接收消息,由于目前还未提供给消息消费者,消息会暂存在队列中。
- 3)消息消费者接收消息
//业务处理类
@Service
public class RabbitMQService {
/*
Publish/Subscribe 工作模式接收、处理邮件业务
*/
@RabbitListener(queues = "fanout_queue_email")
public void psubConsumerEmail(Message message){
byte[] body = message.getBody();
String s = new String(body);
System.out.println("邮件业务接收到消息:"+s);
}
/*
Publish/Subscribe 工作模式接收、处理短信业务
*/
@RabbitListener(queues = "fanout_queue_sms")
public void psubConsumerSms(Message message){
byte[] body = message.getBody();
String s = new String(body);
System.out.println("短信业务接收到消息:"+s);
}
}
使用@RabbitListener注解监听队列名称为fanout_queue_email和fanout_queue_sms的消息,监听的两个队列即为刚才设置的消息队列。
一旦服务启动且监听到指定队列中有消息存在(我们已经传入了消息),对应方法会立即接收并消费队列中的消息。
项目启动会,结果如下图: 再次启动项目,消息队列消息已经被消费,无输出
基于配置类方式
- 使用@Configuration注解配置类定制消息发送组件,使用@Bean注解定制三种类型的Bean组件。
@Configuration
public class RabbitMQConfig {
@Bean
// 防止发送实体类消息时出现异常
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
// 定义fanout类型的交换器
@Bean
public Exchange fanout_exchange(){
return ExchangeBuilder.fanoutExchange("fanout_exchange").build();
}
// 定义两个不同名称的消息队列
@Bean
public Queue fanout_queue_email(){
return new Queue("fanout_queue_email");
}
@Bean
public Queue fanout_queue_sms(){
return new Queue("fanout_queue_sms");
}
// 消息队列与交换器绑定
@Bean
public Binding bindingEmail(){
return BindingBuilder.bind(fanout_queue_email()).to(fanout_exchange()).with("").noargs();
}
@Bean
public Binding bindingSms(){
return BindingBuilder.bind(fanout_queue_sms()).to(fanout_exchange()).with("").noargs();
}
}
在项目启动的情况下,运行消息发送测试方法,可以在控制台看到每次发送自动监听到就会在控制台输出捕捉到的信息。
基于注解方式
- 基于注解的方式是使用Spring框架的@RabbitMQListener注解定制消息发送组件并发送消息。
@Service
public class RabbitMQService {
/*
Publish/Subscribe 工作模式接收、处理邮件业务
*/
// bindings属性用于创建并绑定交换器和消息队列组件,为了能使两个消息组件的消费者接收到实体类User,需要我们在定制交换器时将交换器类型设置为fanout
//bindings属性的@QueueBinding注解除了有value、type属性外,还有key属性用于定制路由键routingKey(当前订阅发布模式不需要)
@RabbitListener(bindings = @QueueBinding(value =
@Queue("fanout_queue_email"),exchange =
@Exchange(value = "fanout_exchange",type="fanout")))
public void pusbConsumerEmailAno(User user){
System.out.println("邮件业务接收到消息:"+user);
}
@RabbitListener(bindings = @QueueBinding(value =
@Queue("fanout_queue_sms"),exchange =
@Exchange(value = "fanout_exchange",type="fanout")))
public void pusbConsumerSmsAno(User user){
System.out.println("短信业务接收到消息:"+user);
}
}
- 基于API的方式相对简单、直观,容易与业务代码产生耦合
- 基于配置类的方式相对隔离、容易统一管理、符合SpringBoot框架思想
- 基于注解的方式清晰明了、方便各自管理,也容易产生耦合
Routing(路由模式)
@Service
public class RabbitMQService {
/*
路由模式消息接收、处理error级别日志信息
*/
@RabbitListener(bindings = @QueueBinding(value =
@Queue("routing_queue_error"),exchange =
@Exchange(value="routing_exchange",type="direct"),
key="error_routing_key"))
public void routingConsumerError(String message){
System.out.println("接收到error级别日志消息:"+message);
}
@RabbitListener(bindings = @QueueBinding(value =
@Queue("routing_queue_all"),exchange =
@Exchange(value="routing_exchange",type="direct"),
key={"error_routing_key","info_routing_key","warning_routing_key"}))
public void routingConsumerAll(String message){
System.out.println("接收到error/error/warning级别日志消息:"+message);
}
}
在测试类中实现Routing路由模式发送消息
// Routing工作模式消息发送端
@Test
public void routingPublisher(){
rabbitTemplate.convertAndSend("routing_exchange","error_routing_key",
"routing send error message");
}
项目启动,运行routingPublisher方法,测试结果如下:
修改"error_routing_key"为"info_routing_key",测试结果:
Topics(通配符模式)
/*
通配符模式消息接收、进行邮件业务订阅处理
*/
@RabbitListener(bindings = @QueueBinding(value =
@Queue("topic_queue_email"),exchange =
@Exchange(value = "topic_exchange",type = "topic"),
key="info.#.email.#"))
public void topicConsumerEmail(String message){
System.out.println("接收到邮件订阅需求处理消息:"+message);
}
@RabbitListener(bindings = @QueueBinding(value =
@Queue("topic_queue_email"),exchange =
@Exchange(value = "topic_exchange",type = "topic"),
key="info.#.sms.#"))
public void topicConsumerSms(String message){
System.out.println("接收到短信订阅需求处理消息:"+message);
}
在测试类中实现Topic通配符模式发送消息
// Topics工作模式消息发送端
@Test
public void topicPublisher(){
// 只发送邮件订阅用户信息
// rabbitTemplate.convertAndSend("topic_exchange","info.email","topics send email message");
// 只发送短信订阅用户信息
//rabbitTemplate.convertAndSend("topic_exchange","info.sms","topics send sms message");
// 同时发送
rabbitTemplate.convertAndSend("topic_exchange","info.email.sms","topics send email and sms message");
}
可以看出,使用基于注解的方式自动生成了Topics通配符模式下的消息组件,并进行了自动绑定。