注:实践内容参考人民邮电出版社的教程《 Spring Boot企业级开发教程》作者:黑马程序员,上传本文仅以实践过程以供大家共同学习解决问题,如有侵权不当行为,请告知后,我会更正或删除。
2.RabbitMQ安装
(3)配置环境变量
安装完RabbitMQ后,系统环境变量会自动增加一个变量名为ERLANG——HOME的变量配置,配置路径是Erlang选择安装的具体路径,无需修改。如图:
选择用户变量path,添加ERLANG_HOME环境变量,如图:
3.RabbitMQ可视化效果展示
运行安装后开始菜单下的RabbitMQ Server的RabbitMQ Comand Prompt,输入 rabbitmqctl status ,如图,说明安装成功。
输入命令rabbitmq-plugins enable rabbitmq_management,这样就可以添加可视化插件了
(2)在全局配置文件添加RabbitMQ消息中间件的连接配置
# 配置RabbitMQ消息中间件连接配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#配置RabbitMQ虚拟主机路径/,默认可以省略
spring.rabbitmq.virtual-host=/
Spring Boot对RabbitMQ的6种工作模式都进行了非常好的整合实现,并集成了多种方式的整合支持,包括基于API的方式、基于配置类的方式、基于注解的方式。下面,选取常用的三种工作模式完成在Spring Boot项目中的消息服务整合实现。
Spring Boot整合RabbitMQ中间件实现消息服务,主要围绕三个部分的工作进行展开:定制中间件、消息发送者发送消息、消息消费者接收消息 。下面,以用户注册成功后同时发送邮件通知和短信通知这一场景为例,分别使用基于API,基于配置类和基于注解这三种方式实现Publish/Subscribe工作模式的整合。
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));
}
2)消息发送者发送消息
完成消息组件的定制工作后,创建消息发送者发送消息到消息队列中,在进行发送消息时,将会定制一个实体类进行消息传送,需要预先创建一个实体类对象。
在项目测试类中添加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面板查看队列消息情况,会发现两个队列中存储的消息已经自动删除。如图:
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(),两者测试效果相同,消息消费者可以自动监听并消费消息队列中存在的消息。
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);
}
}
这里,我们以不同级别日志信息采集处理这一场景为例,使用基于注解的方式来实现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(),效果如图:
以不同用户对邮件和短信的订阅需求这一场景为例,使用使用基于注解的方式来实现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()效果如图: