RabbitMQ 的概念以及好处作用我就不说了,这里直接是整合的实例。
我用的idea开发,这里先放一张目录结构图
这里我建了三个独立的springboot项目,因为实际开发都是通过消息队列远程传输,然后接受消息实现业务的
idea如何同时打开多个项目:其实我的做法就是直接新建一个maven项目,然后右键这个项目新建Module,这每一个Module就是一个独立的项目,建好这三个Module后,可以将最外层那个项目里面的结构全部删除,这时idea就会提示是否去掉他,选是,就变成上图三个独立项目的结构(这三个都是springboot项目)
1.springboot 整合 RabbitMQ
首先可定是pom.xml文件啦,一个发送端的项目和两个接受端的项目都要引入这个依赖
springboot是通过amqp来对消息队列进行整合的,使用起来非常便捷,相比原生的rabbitmq用法,这简直方便到极致
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
然后配置application 配置文件,这个是发送端的配置,另外两个接收端只需要修改第一个项目名的配置,和项目端口号(因为我这三个项目都是本地运行模拟下的,端口号肯定要不一样),当然我这里使用的rabbitmq客户端是本地的,如果你是外网的,ip端口请自行修改
spring.application.name=spirng-boot-rabbitmq-sender
spring.rabbitmq.host=127.0.0.1
#这里端口是5672,不是15672...15672是管理端的端口,发送端跟接收端的ip和端口都要一样
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
server.port=8080
好了,到这里springboot就整合好了rabbitmq了,什么?就这样?没错,springboot就是这么简单,后面就全是在springboot里如何使用rabbitmq了。
RabbitMQ的Direct模式用法
direct 模式 (一对一),即一个发送端发送的消息,只能被一个接收端接受,就算有多个项目同时监听这个队列,也只能只有一个受到消息
1)首先新建一个配置类,该类是用来注入队列到容器中去的
(rabbitmq支持传输字符串和自定义对象,最下面那个bean我们用来传输自定义对象)
只需要在发送端新建该配置类即可,接收端不用
@Configuration
public class SenderConf {
// Direct模式
@Bean
public Queue queue() {
return new Queue("queue");
}
@Bean
public Queue queue2() {
return new Queue("queue2");
}
@Bean
public Queue orderQueue() {
return new Queue("orderQueue");
}
}
2)在发送端和接收端1,新建一个用来rabbirmq传输的实体类,测试rabbitmq通过对象来传输
注意:如果要在rabbitmq传输对象,发送端和接收端的这个传输类 必须要实现序列化接口,还有两边的项目对应这个传输类的包名必须一样,缺一不可
package com.liqiye.bean;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author liqiye
* @description 订单 如果是rabbitmq里面要用对象传输一定要实现序列化接口
* @date 2019/6/3
*/
public class Order implements Serializable {
private String id; // 订单号
private String name; // 订单名
private Date Ordertime; // 下单时间
private int num; // 数量
private BigDecimal price; // 价格
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getOrdertime() {
return Ordertime;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public void setOrdertime(Date ordertime) {
Ordertime = ordertime;
}
@Override
public String toString() {
return "Order{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", Ordertime=" + Ordertime +
", num=" + num +
", price=" + price +
'}';
}
}
3)在发送端项目新建controller ,编写发送消息到消息队列的接口
@Controller
public class SenderController {
@Autowired
private AmqpTemplate template;
// direct 模式 (一对一)就算有多个项目同时监听这个队列,也只能只有一个受到消息
@RequestMapping("/send1")
@ResponseBody
public String send() {
// 业务逻辑代码
// 发送消息到消息队列
template.convertAndSend("queue","hello,rabbit~");
return "发送消息到队列成功";
}
@RequestMapping("/send2")
@ResponseBody
public String send2() {
// 业务逻辑代码
// 发送消息到消息队列
template.convertAndSend("queue2","hello,rabbit~");
return "发送消息到队列成功";
}
// 注意:如果要在rabbitmq传输对象,发送端和接收端的这个传输类 必须要实现序列化接口,
// 还有两边的项目对应这个传输类的包名必须一样,缺一不可
@RequestMapping("/send3")
@ResponseBody
public String send3() {
// 业务逻辑代码
// 发送消息到消息队列
Order order = new Order();
order.setId("1");
order.setName("手机");
order.setOrdertime(new Date());
template.convertAndSend("orderQueue",order);
return "发送消息到队列成功";
}
}
4)接收端配置监听器去监听绑定到的消息队列
在receive项目下新建
@Component
public class Receive {
// direct模式
@RabbitListener(queues="queue") //监听器监听指定的queue
public void processC(String str) {
System.out.println("Receive:"+str);
}
@RabbitListener(queues="orderQueue") //监听器监听指定的queue
public void processC2(Order order) {
// 通知库存系统,发货 等操作
System.out.println("接受到订单信息:"+order.toString());
System.out.println("后续功能...");
}
}
在receive2项目下新建
@Component
public class Receive {
// direct模式
@RabbitListener(queues="queue2") //监听器监听指定的queue
public void processC(String str) {
System.out.println("Receive2:"+str);
}
}
5)测试
分别启动三个springboot项目,这里建议先启动发送端,然后先去访问一下发送消息的接口,让他在rabbitmq先形成这些队列,不然可能启动接收端项目时,会报找不到指定队列的错误。
发送 http://localhost:8080/send1
发送 http://localhost:8080/send2
发送 http://localhost:8080/send3
可以看到我们在 sender项目发出的消息,经过消息队列的传输,到达了对应接收端项目,接收端的监听器类,会自动监听消息,收到消息后,会自动进入对应方法执行
上面理解了rabbitmq的简单用法后,下面的topic和fanout模式我就简单带过了
RabbitMQ的Topic模式用法
topic 模式,发送消息时需要指定交换机跟key,找到交换机对应key的队列,发送消息进去,就算有多个项目同时监听这个队列,也只能只有一个收到消息
在 SenderConf 配置类 加上
// Topic转发模式,配置队列Queue,再配置交换机(Exchange),再把队列按照相应的规则绑定到交换机上
@Bean(name="topic1")
public Queue queueMessage() {
return new Queue("topic.topic1");
}
@Bean(name="topic2")
public Queue queueMessages() {
return new Queue("topic.topic2");
}
@Bean(name="exchange")
public TopicExchange exchange() {
return new TopicExchange("exchange");
}
@Bean
Binding bindingExchangeMessage(@Qualifier("topic1") Queue queueMessage,@Qualifier("exchange") TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.topic1");
}
@Bean
Binding bindingExchangeMessages(@Qualifier("topic2") Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");//*表示一个词,#表示零个或多个词
}
在 senderController 加上
// --------- topic 模式,在配置类@Configuration里面,将队列绑定到交换机,还可以用匹配符号, ---------------------------------
// 这里发送消息时需要指定交换机跟key,找到交换机对应key的队列,发送消息进去,
// 就算有多个项目同时监听这个队列,也只能只有一个收到消息
@RequestMapping("/send4")
@ResponseBody
public String send4(){
// 业务逻辑代码
// 发送消息到消息队列
// template.convertAndSend("exchange","topic.topic2","消息");
template.convertAndSend("exchange","topic.topic1","消息");
return "发送消息到队列成功";
}
在两个接收端项目都加上
// topic模式
@RabbitListener(queues="topic.topic1") //监听器监听指定的Queue
public void process1(String str) {
System.out.println("topic1:"+str);
}
@RabbitListener(queues="topic.topic2") //监听器监听指定的Queue
public void process2(String str) {
System.out.println("topic2:"+str);
}
RabbitMQ的Fanout模式用法
Fanout Exchange 广播模式,发送消息时只需要指定广播路由器名字,就会将消息发送到绑定的所有队列里面去,就算有多个项目同时监听同一个队列,也只能只有一个收到消息
在发送端项目的 SenderConf 加上
// Fanout Exchange 广播模式,配置队列Queue,再配置广播路由器(FanoutExchange),
// 再把队列按照相应的规则绑定到广播路由器上,不需要指定key,就算指定了也不生效
@Bean(name="Afanout")
public Queue Afanout() {
return new Queue("fanout.A");
}
@Bean(name="Bfanout")
public Queue Bfanout() {
return new Queue("fanout.B");
}
@Bean(name="fanoutExchange")
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");//配置广播路由器
}
@Bean
Binding bindingExchangeA(@Qualifier("Afanout") Queue Afanout,@Qualifier("fanoutExchange")FanoutExchange fanoutExchange) {
return BindingBuilder.bind(Afanout).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(@Qualifier("Bfanout") Queue Bfanout,@Qualifier("fanoutExchange")FanoutExchange fanoutExchange) {
return BindingBuilder.bind(Bfanout).to(fanoutExchange);
}
在 发送端的 SenderController 加上
// ----------Fanout Exchange 广播模式,在配置类@Configuration里面,将队列绑定到广播路由器------
// 这里发送消息时只需要指定广播路由器名字,就会将消息发送到绑定的所有队列里面去,
// 就算有多个项目同时监听同一个队列,也只能只有一个收到消息
@RequestMapping("/send5")
@ResponseBody
public String send5(){
// 业务逻辑代码
// 发送消息到消息队列
template.convertAndSend("fanoutExchange","","消息");
return "发送消息到队列成功";
}
在两个接收端项目都加上
// Fanout Exchange 广播模式
@RabbitListener(queues="fanout.A")
public void processA(String str) {
System.out.println("fanoutA:"+str);
}
@RabbitListener(queues="fanout.B")
public void processB(String str) {
System.out.println("fanoutB:"+str);
}
header 模式 不常用就不做了