注:实践内容参考人民邮电出版社的教程《 Spring Boot企业级开发教程》作者:黑马程序员,上传本文仅以实践过程以供大家共同学习解决问题,如有侵权不当行为,请告知后,我会更正或删除。
1 消息服务概述
1.1 为什么 要使用消息服务
1.2 常用消息中间件介绍
2 RabbitMQ消息中间件
2.1 RabbitMQ简介
2.2 RabbitMQ工作模式介绍
3 RabbitMQ安装以及整合环境搭建
3.1 安装RabbitMQ
2.RabbitMQ安装
- (1)安装Erlang语言包,这里演示电脑为64位,安装的是otp_win64_21.2.exe
安装过程提示的运行组件也请一并安装
- (2)成功安装语言包后安装Rabbitmq,这里演示安装的是rabbitmq-server-3.7.9.exe
-
(3)配置环境变量
安装完RabbitMQ后,系统环境变量会自动增加一个变量名为ERLANG——HOME的变量配置,配置路径是Erlang选择安装的具体路径,无需修改。如图:
选择用户变量path,添加ERLANG_HOME环境变量,如图:
3.RabbitMQ可视化效果展示
-
运行安装后开始菜单下的RabbitMQ Server的RabbitMQ Comand Prompt,输入 rabbitmqctl status ,如图,说明安装成功。
-
输入命令rabbitmq-plugins enable rabbitmq_management,这样就可以添加可视化插件了
3.2 Spring Boot整合RabbitMQ环境搭配
-
-
(1)使用Spring Initializr方式创建项目,选择Web依赖和RabbitMQ依赖,如图:
-
(2)在全局配置文件添加RabbitMQ消息中间件的连接配置
# 配置RabbitMQ消息中间件连接配置 spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest #配置RabbitMQ虚拟主机路径/,默认可以省略 spring.rabbitmq.virtual-host=/
4 Spring Boot与RabbitMQ整合实现
Spring Boot对RabbitMQ的6种工作模式都进行了非常好的整合实现,并集成了多种方式的整合支持,包括基于API的方式、基于配置类的方式、基于注解的方式。下面,选取常用的三种工作模式完成在Spring Boot项目中的消息服务整合实现。
4.1 Publish/Subscribe(发布订阅模式)
Spring Boot整合RabbitMQ中间件实现消息服务,主要围绕三个部分的工作进行展开:定制中间件、消息发送者发送消息、消息消费者接收消息 。下面,以用户注册成功后同时发送邮件通知和短信通知这一场景为例,分别使用基于API,基于配置类和基于注解这三种方式实现Publish/Subscribe工作模式的整合。
1.基于API的方式
-
1)使用AmqpAdmin定制消息发送组件
-
在项目的测试类Chapter08ApplicationTests.java中引入AmqpAdmin管理类定制Publish/Subscribe工作模式所需的消息组件,内容如下:
@Autowired private AmqpAdmin amqpAdmin; //使用AmqpAdmin管理员API定制消息组件 @Test public void amqpAdmin() { // 1、定义fanout类型的交换器 amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange")); // 2、定义两个默认持久化队列,分别处理email和sms amqpAdmin.declareQueue(new Queue("fanout_queue_email"));//注意对Queue正确导包 amqpAdmin.declareQueue(new Queue("fanout_queue_sms")); // 3、将队列分别与交换器进行绑定 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)); }
-
执行测试类amqpAdmin(),可看到效果
-
点击RabbitMQ中的fanout_exchange,可以查看到两个默认持久化队列
-
点击队列Queues,可以查看消息信息发送和接收情况,如图:
-
-
2)消息发送者发送消息
完成消息组件的定制工作后,创建消息发送者发送消息到消息队列中,在进行发送消息时,将会定制一个实体类进行消息传送,需要预先创建一个实体类对象。
-
在项目中创建domain包,并在该包下创建一个实体类User,User.java内容如图:
-
在项目测试类中添加Spring框架提供的RabbitTemplate模板类实现消息发送,代码如下:
@Autowired private RabbitTemplate rabbitTemplate; //Publish/Subscribe工作模式消息发送端 @Test public void psubPublisher() { User user=new User();//注意对User对象进行正确导包为自定义的User实体类 user.setId(1); user.setUsername("石头"); //RabbitTemplate模板类实现消息发送,第1个参数为交换器,第二个参数为路由键,使用Publish/Subscribe工作模式可以为空,第三个参数为发送的消息内容,接收Object类型 rabbitTemplate.convertAndSend("fanout_exchange","",user); }
-
-
在项目com.itheima下中创建config包,并在该包下创建一个RabbitMQ消息配置类RabbitMQConfig,实现JSON格式消息转换器替换默认转换器,内容如下:
package com.itheima.config; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQConfig { //定制JSON格式的消息转换器 @Bean //把返回值存到容器供使用 public MessageConverter messageConverter(){ return new Jackson2JsonMessageConverter(); } }
-
再运行测试方法 psubPublisher(),进行消息的发布,执行成功后刷新http://localhost:15672/#/queues,效果如图:
可以看到Ready为1,消息发布成功并暂存在队列中。 -
3)消息接收者接收消息
-
在项目com.itheima下创建包service,在包下创建一个针对对RabbitMQ消息中间件进行消息接收和处理的业务类RabbitMQService.java,内容如下:
package com.itheima.service; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Service; @Service public class RabbitMQService { // * Publish/Subscribe工作模式接收,处理邮件业务 @RabbitListener(queues = "fanout_queue_email")//监听"fanout_queue_email"的消息 public void psubConsumerEmail(Message message) {//Message导入含amqp的包 byte[] body = message.getBody(); String s = new String(body); System.out.println("邮件业务接收到消息: "+s); } // Publish/Subscribe工作模式接收,处理短信业务 @RabbitListener(queues = "fanout_queue_sms") //监听"fanout_queue_sms"的消息 public void psubConsumerSms(Message message) { byte[] body = message.getBody(); String s = new String(body); System.out.println("短信业务接收到消息: "+s); } }
-
启动项目核心引导类,运行效果如图:
可以看到,控制台输出了监听到的消息后的处理。并通过RabbitMQ可视化管理页面的Queues面板查看队列消息情况,会发现两个队列中存储的消息已经自动删除。如图:
-
2.基于配置类的方式
package com.itheima.config;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
//定制JSON格式的消息转换器
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
//使用基于配置类的方式定制消息中间件,流程与测试类中使用AmqpAdmin管理员API定制消息组件类同,
//不同之处是一个通过测试类实现,一个通过配置类实现
// 1、定义fanout类型的交换器
@Bean
public Exchange fanout_exchange(){//导入org.springframework.amqp.core.*;
return ExchangeBuilder.fanoutExchange("fanout_exchange").build();
}
// 2、定义两个不同名称的消息队列
@Bean
public Queue fanout_queue_email(){
return new Queue("fanout_queue_email");
}
@Bean
public Queue fanout_queue_sms(){
return new Queue("fanout_queue_sms");
}
// 3、将两个不同名称的消息队列与交换器进行绑定
@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();
}
}
注释Chapter08ApplicationTests.java中的使用AmqpAdmin管理员API定制消息组件部分的代码,运行psubPublisher(),两者测试效果相同,消息消费者可以自动监听并消费消息队列中存在的消息。
3.基于注解的方式
package com.itheima.service;
import com.itheima.domain.User;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class RabbitMQService {
/*// * Publish/Subscribe工作模式接收,处理邮件业务
@RabbitListener(queues = "fanout_queue_email")//监听"fanout_queue_email"的消息
public void psubConsumerEmail(Message message) {//Message导入含amqp的包
byte[] body = message.getBody();
String s = new String(body);
System.out.println("邮件业务接收到消息: "+s);
}
// Publish/Subscribe工作模式接收,处理短信业务
@RabbitListener(queues = "fanout_queue_sms") //监听"fanout_queue_sms"的消息
public void psubConsumerSms(Message message) {
byte[] body = message.getBody();
String s = new String(body);
System.out.println("短信业务接收到消息: "+s);
}*/
//1.1、Publish/Subscribe工作模式接收,处理邮件业务
@RabbitListener(bindings =@QueueBinding(value =@Queue("fanout_queue_email"), exchange =@Exchange(value = "fanout_exchange",type = "fanout")))
public void psubConsumerEmailAno(User user) {
System.out.println("邮件业务接收到消息: "+user);
}
//1.2、Publish/Subscribe工作模式接收,处理短信业务
@RabbitListener(bindings =@QueueBinding(value =@Queue("fanout_queue_sms"),exchange =@Exchange(value = "fanout_exchange",type = "fanout")))
public void psubConsumerSmsAno(User user) {
System.out.println("短信业务接收到消息: "+user);
}
}
4.2 Routing路由模式
这里,我们以不同级别日志信息采集处理这一场景为例,使用基于注解的方式来实现Routing路由模式的整合讲解。
-
1)使用基于注解的方式定制消息组件和消息消费者
-
打开进行消息接收和处理的业务类RabbitService,注释掉之前Publish/Subscribe工作模式。
-
在该类中使用@RabbitListener注解及其相关属性定制Routing路由模式的消息组件,代码如下:
//2.1、路由模式消息接收,处理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); } //2.2、路由模式消息接收,处理info、error、warning级别日志信息 @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("接收到info、error、warning等级别日志消息: "+message); }
-
-
2)消息发送者发送消息
打开测试类,添加Routing工作模式消息发送端,代码如下:
//2、Routing工作模式消息发送端 @Test public void routingPublisher() { rabbitTemplate.convertAndSend("routing_exchange","error_routing_key","routing send error message"); //参数说明:"routing_exchange":交换器名称;"error_routing_key":当前消息的日志级别error级别;"routing send error message":具体要发送的消息 }
-
3)运行测试类中的routingPublisher(),效果如图:
查看浏览器端,交换器(Exchanges)多了routing_exchange,如图:
Queues也多了routing_queue_all和routing_queue_error,如图:
4.3 Topic(通配符模式)
以不同用户对邮件和短信的订阅需求这一场景为例,使用使用基于注解的方式来实现Topic(通配符模式)的整合讲解。
-
1)使用基于注解的方式定制消息组件和消息消费者
-
打开进行消息接收和处理的业务类RabbitService,在该类中使用@RabbitListener注解及其相关属性定制Topics路由模式的消息组件,代码如下:
//3.1、通配符模式消息接收,进行邮件业务订阅处理 @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); } //3.2、通配符模式消息接收,进行短信业务订阅处理 @RabbitListener(bindings =@QueueBinding(value =@Queue("topic_queue_sms"),exchange =@Exchange(value = "topic_exchange",type = "topic"),key = "info.#.sms.#")) public void topicConsumerSms(String message) { System.out.println("接收到短信订阅需求处理消息: "+message); }
-
-
2)消息发送者发送消息
在测试类中使用RabbitTemplate模板类实现Routing路由模式下的消息 发送,示例代码如下:
@Test public void topicPublisher() { // 1、只发送邮件订阅用户消息 // rabbitTemplate.convertAndSend("topic_exchange","info.email","topics send email message"); // 2、只发送短信订阅用户消息 // rabbitTemplate.convertAndSend("topic_exchange","info.sms","topics send sms message"); // 3、发送同时订阅邮件和短信的用户消息 rabbitTemplate.convertAndSend("topic_exchange","info.email.sms","topics send email and sms message"); }
-
3)这里提供了三种发送方式 ,我们可以一一测试,如这里使用第3种,发送同时订阅邮件和短信的用户消息 ,运行topicPublisher()效果如图:
浏览器查阅效果同样增加了相关Exchanges和queues,如图: