目录


一.准备工作

本次入门是在原先创建的SpringBoot基础上添加可以点击此处查看

1.项目结构分析

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java

​pom.xml​​添加RabbitMq依赖文件

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<!-- <version>2.6.1</version>--><!--由于前面已经定义了springboot的版本号这里省略-->
</dependency>

由于前面已经定义了springboot的版本号这里省略

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_02

项目中还使用到了hutool工具:一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
</dependency>

配置application.yml

rabbitmq: #设置rabbitMq的配置
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_03

2.了解相关知识


Broker:简单来说就是消息队列服务器实体。 Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。 producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。


二.Direct模式

Direct模式相当于点对点模式,一个消息被发送者发送后,会被转发到通过routingkey绑定到具体消息队列中,然后被一个接收者接收!

1.Direct配置编写

在config创建DirectConfig类用于配置队列和路由等信息绑定

@Configuration
public class DirectConfig {


/**
* 路由关键字
*/
public static final String ROUTING_ORDER="direct_order_routing";//订单的路由
/**
* 创建队列
*/
public static final String QUEUE_OREDER="direct_order_message";//订单的队列

/**
* 配置交换机
*/
public static final String DIRECT_EXCHANGE="direct";//direct类型交换机

/**
* 声明队列
* @return
*/
@Bean
public Queue directQueue(){
//持久 - 如果我们声明一个持久队列,则为真(该队列将在服务器重启后继续存在)
return new Queue(QUEUE_OREDER,false);
}


/**
* 声明交换机
* @return
*/
@Bean
public DirectExchange directExchange(){
//交换器名称、是否持久化、是否自动删除
return new DirectExchange(DIRECT_EXCHANGE,true,false);
}

/***
* 队列绑定到交换机上
* 并且设置路由关键字
*/
@Bean
public Binding binding(Queue queue,DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_ORDER);
}

}

2.创建消费者

Consumer包下创建订单的消费者OrderConsumer

​@RabbitListener​​可以作用在类上面,需配合 @RabbitHandler 注解一起使用也可以配置方法上就不需要@RabbitHandler

​@RabbitListener(queues = {"direct_order_message"})​​可以监听多个队列我这里只监听了一个名称是​​direct_order_message​​的队列

@Component
@RabbitListener(queues = {"direct_order_message"})//队列名称(direct_order_message)
public class OrderConsumer {
private static final Logger logger= LoggerFactory.getLogger(OrderConsumer.class);

@RabbitHandler//区分消息的内容信息运行不同的方法
public void handler(Map message){
//logger.info("OrderConsumer处理订单信息:"+message.toString());
System.out.println("OrderConsumer处理订单信息:"+message.toString());
}


}

3.创建生产者

Producer包下创建生产者用于生产信息SenderOrderProducer

/**
* 生产者--发送消息
*/
@Component
public class SenderOrderProducer {

private static final Logger logger = LoggerFactory.getLogger(SenderOrderProducer.class);

@Autowired
private RabbitTemplate rabbitmqTemplate;//创建rqbbit模板对象

/**
* 发送信息
* @param exchange 交换机名称
* @param routingKey 路由键
* @param message 数据信息
*/
public void send(String exchange, String routingKey,Object message){
//logger.info("存入队列的消息:"+message);
System.out.println("存入队列的消息:"+message);
rabbitmqTemplate.convertAndSend(exchange,routingKey,message);
}

}

4.创建Direct接口测试

Controller包下创建RabbitMqController用于对外调用查看信息使用到swagger注解生成在线文档(可以看往前文章)

@Api(description = "RabbitMq")
@Component
@RequestMapping("rabbitMq")
public class RabbitMqController {

@Autowired
private SenderOrderProducer orderProducer;//生产者对象

@ApiOperation(value = "订单信息")
@PostMapping("transferOrder")
public ResponseEntity<Void> testOrder(@ApiParam(value = "数据信息",required = true) @RequestParam String message){
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",message);
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(DirectConfig.DIRECT_EXCHANGE,DirectConfig.ROUTING_ORDER,map);
return ResponseEntity.noContent().build();
}


}

运行服务服务swagger网页:​​ip:服务的端口/swagger-ui.html​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_04

发送请求

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_05

队列中的信息被消费

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_06

5.模拟多个消费者

模拟下多个消费者来获取rabbit的信息

我们把OrderConsumer类复制一份,修改打印的信息做一个标识和之前的消费者做个区分

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_07

由于请求只会往队列插入一条信息,我们需要改造​​RabbitMqController​​循环插入信息

@ApiOperation(value = "订单信息")
@PostMapping("transferOrder")
public ResponseEntity<Void> testOrder(@ApiParam(value = "数据信息",required = true) @RequestParam String message){
for (int i = 0; i < 6; i++) {
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",message);
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(DirectConfig.DIRECT_EXCHANGE,DirectConfig.ROUTING_ORDER,map);
}
return ResponseEntity.noContent().build();
}

调用swagger运行接口,可以看出往队列添加了6条数据,并且消费者2个已经​​分别对信息进行消费,并且他们不会消费重复数据可以看uuid是否有重复来区分是否重复消费​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_08

创建一个对象用于接受前端传递过来的json数据,创建Pojo包下面在创建一个订单实体类

注意:一定要把实体类实现Serializable接口,不然传递给rabbit会报错

/**
* 订单实体类
*/
public class OrderEntity implements Serializable {
/**
* 订单号
*/
private String orderNo;
/**
* 创建时间
*/
private String createTime;
/**
* 金额
*/
private BigDecimal amount;
//省略get/set/toString方法
}

RabbitMqController类添加新接口

这一次我们传递的信息是订单对象,不像之前传递过去的是字符串

@ApiOperation(value = "订单信息")
@PostMapping("createOrder")
public ResponseEntity<Void> createOrder(@ApiParam(value = "订单数据",required = true) @RequestBody OrderEntity orderEntity){
for (int i = 0; i < 6; i++) {
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",orderEntity);//传递订单对象
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(DirectConfig.DIRECT_EXCHANGE,DirectConfig.ROUTING_ORDER,map);
}
return ResponseEntity.noContent().build();
}

重新运行项目,访问swaggerSpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_09

数据被消费者分别消费成功

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_10
测试没有消费者,只把数据传递到队列中

把2个消费者的​​@RabbitListener​​和​​@RabbitHandler​​都注释

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_11

重启项目在运行接口把信息传递到队列中,因为消费者已经没有了所以数据会存放在rabbit中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_12

我们可以访问Rabbiymq的地址查看:​​运行rabbitmq的ip:15672​

没有改动的话一般都是端口15672 ​​默认用户名和密码都是:guest​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_13

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_14

我们在调用接口

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_15

看控制台又插入6条数据到队列中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_16

在通过浏览器查看rabbitmq管理界面队列已经有12条数据了

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_17

现在我们重启没有调用接口是不会往队列在创建数据,这个时候我们把消费者的注释都去除,相当于有2个消费者会消费队列里面的信息数据

消费者1:

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_18

消费者2:

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_19

运行后:​效果是消费者1消费了所有数据​出现这种情况也可能是因为消费者1先被spring创建了导致消费者2被创建出来后,可能已经全部被先创建的消费者1消费光了(这个的可能性大些)

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_20

我先排除下是不是因为消费者2没被创建出来所以导致消费者1全部消费完成.

在我只要请求一下接口看一下会不会有消费者2出来消费数据

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_21

可以看出消费者2是存在的,并且这6条数据是for循环调用插入队列中,可以看出for在运行第4条还没有插入完成,消费端就已经开始消费信息了

6.单消费者运行耗时程序

只用一个消费者消费信息,我们通过休眠模拟业务这里休眠9秒

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_22

我们现在调用接口插入6条数据到队列中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_23

可以看出由于业务比较耗时已经在一条一条的处理中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_24

rabbitmq管理界面也展示出正在消费中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_25

三.Topic转发模式

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_26

可以看出消息是通过routing key与binding key的匹配关系进行路由的匹配,key可以由多个单词进行匹配通过​​.​​来隔开,其中需要注意的是​​2个通配符​​:​​#​​匹配一个或者多个,​​*​​匹配一个

1.前期准备

注意​:为了测试Topic转发模式我们需要把Direct模式用到的类都删除,避免影响到Topic的测试,我这的做法是把​​Direct使用到的类@Configuration​​和​​@Component​​注释这样spring就不会加载这个对象

DirectConfig配置类注释上

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_27

OrderConsumer消费者类注释上

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_28

把订单的消费者2删除掉

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_29

在把RabbitMqController的配置注释上这样swagger就不会展示Direct测试接口

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_30

2.Topic配置编写

在config包下创建TopicConfig配置,创建路由关键字,队列名称,创建交换机,在配置交换机和队列的关系.

注意​:在Spring中通过​​@Bean​​创建对象时,如果多个bean的类型是一样的我们需要使用​​@Qualifier()​​来指定使用的是那个@Bean,如果​​@Bean(name="cs")​​没有指定name属性那么@Qualifier()里面填写的就是方法的名称,你可以在这个绑定交换机和队列的方法上看到参数有使用这个注解​​@Qualifier()​

/**
* Topic模式
*/
@Configuration
public class TopicConfig {


/**
* 路由关键字
*/
public static final String ROUTING_ORDER="direct.order.routing";//订单的路由关键字
public static final String ROUTING_WMS="direct.wms.routing";//库存的路由关键字
/**
* 创建队列名称
*/
public static final String QUEUE_TPOIC_ORDER="topic_order_message";//订单的队列
public static final String QUEUE_TPOIC_WMS="topic_wms_message";//库存的队列

/**
* 配置交换机
*/
public static final String TOPIC_EXCHANGE="topic";//topic类型交换机

/**
* 声明队列
* @return
*/
@Bean
public Queue topicQueueOrder(){
//true持久 - 如果我们声明一个持久队列,则为真(该队列将在服务器重启后继续存在)
return new Queue(QUEUE_TPOIC_ORDER,true);
}
@Bean
public Queue topicQueueWms(){
//true持久 - 如果我们声明一个持久队列,则为真(该队列将在服务器重启后继续存在)
return new Queue(QUEUE_TPOIC_WMS,true);
}


/**
* 声明交换机
* @return
*/
@Bean
public TopicExchange topicExchange(){
//交换器名称、是否持久化、是否自动删除
return new TopicExchange(TOPIC_EXCHANGE,true,false);
}

/***
* 队列绑定到交换机上
* 并且设置路由关键字
*/
@Bean
public Binding bindingExchangeOrder(@Qualifier("topicQueueWms") Queue queue, TopicExchange topicExchange){

return BindingBuilder.bind(queue).to(topicExchange).with(ROUTING_WMS);
}

/***
* 队列绑定到交换机上
* 并且设置路由关键字
*/
@Bean
public Binding bindingExchangeWms(@Qualifier("topicQueueOrder") Queue queue, TopicExchange topicExchange){

return BindingBuilder.bind(queue).to(topicExchange).with(ROUTING_ORDER);
}



}

3.创建Topic接口测试

RabbitMqController创建2个接口一个是发一条数据到队列,一个是多条数据到队列并且对象是订单对象

生产者类不需要改动,我们只要把传人的数据改成TopicConfig的交换机和路由的键

@ApiOperation(value = "Topic:订单信息")
@PostMapping("transferOrderTopic")
public ResponseEntity<Void> transferOrderTopic(@ApiParam(value = "数据信息",required = true) @RequestParam String message){
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",message);
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(TopicConfig.TOPIC_EXCHANGE,TopicConfig.ROUTING_ORDER,map);
return ResponseEntity.noContent().build();
}
@ApiOperation(value = "Topic:仓库信息创建多条到队列中")
@PostMapping("createWmsTopic")
public ResponseEntity<Void> createWmsTopic(@ApiParam(value = "仓库数据",required = true) @RequestBody OrderEntity wmsEntity){
for (int i = 0; i < 6; i++) {
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",wmsEntity);
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(TopicConfig.TOPIC_EXCHANGE,TopicConfig.ROUTING_WMS,map);
}
return ResponseEntity.noContent().build();
}

运行项目,观察swagger页面接口已经发生改变,已经有我们定义的接口了.

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_31

我们调用接口发送一条数据到队列中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_32

可以看出已经把信息发送到队列中去了,传输的数据是​​cs2​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_33

我们调用swagger的接口是​​transferOrderTopic​​,我们在通过交换机名称和路由关键字来查找队列的名称

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_34

我们在看TopicConfig配置类来查找对应的队列

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_35

找到对应的队列名称后

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_36

我们通过浏览器访问rabbitmq查看队列​​http://服务的ip:15672/​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_37

可以看出已经有一条信息在队列中因为我们没有写消费者,所以会堆积在队列中,​​点击队列的名称​​到当前页面

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_38

可以看出数据是进行加密的

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_39

4.创建消费者

在Consumer包下创建TopicConsumer消费者创建2个方法来消费对应的对象信息!

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_40

@Component
public class TopicConsumer {
private static final Logger logger= LoggerFactory.getLogger(TopicConsumer.class);

@RabbitListener(queues = {"topic_order_message"})//队列名称(topic_order_message)
public void topicOrder(Map message){
System.out.println("topicOrder处理信息:"+message.toString());
System.out.println("处理订单完成:"+message.get("MESSAGE"));
}
@RabbitListener(queues = {"topic_wms_message"})//队列名称(topic_wms_message)
public void topicWms(Map message){
System.out.println("topicWms处理信息:"+message.toString());
System.out.println("处理订单完成:"+message.get("MESSAGE"));
}


}

运行程序,记得之前没有消费者我们就已经往队列里面添加了一条数据信息,现在我们启动的话应该会被消费掉在看一眼界面

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_41

运行完成后控制台已经打印消费信息了

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_42

可以看出信息从Rabbitmq获取出来后信息被解密成正常的数据了,而且不像我们之前在RabbiMq管理界面看到的密文一样.

在测试下仓库创建多条数据到队列中的情况一次传递的是订单对象

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_43

调用完成后可以看出入队列和消费队列的信息了

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_44

乍一看怎么感觉和Direct模式差不多,你是不是忘记了Topic可是具备转发功能的,而且Direct是点对点的传播,接下来测试转发功能!

5.Topic转发

前面说道消息是通过routing key与binding key的匹配关系进行路由的匹配分发那么改代码 ,现在我们尽量代码改动最小来展示转发,前面我们写了2个接口一个是订单的一个是wms的我们修改路由的关键字

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_45

改成以下

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_46

其他都不变,在重新运行程序调用订单的那个接口

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_47

可以看出存进去队列一条信息被被分发到了2个队列中然后,消费者把队列的数据进行消费

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_48

解释下

因为controller调用的方法使用的是TopicConfig的ROUTING_ORDER常量

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_49

字符串就是​​topic.routing.order​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_50

又因为我们定义了一个路由关键词叫 ​​ROUTING_WMS​​对应的字符串是​​"topic.routing.#"​​,而且绑定的时候队列和关键字进行了绑定

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_51

导致​​路由关键字只要是#可以匹配多个词​​之前的一样都会被转发到这个队列中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_52

​注意:的是由于我们队列是设置成了true持久化的导致后续测试​​*​​代表一个的也触发了转发到对应的队列中,就算我们重启项目队列也依然存在,知道是裂开了后面登录Rabbitmq管理界面才发现这个问题改成false会打印一些提示信息不用管​SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_53

在使用通配符​​*​​匹配一个修改配置改成​​*​SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_54

可以正常转发

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_55

那我把​​路由关键字在添加一个单词看看还能不能转发用​​.​​隔开哦​

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring boot_56

可以看出没有被转发到另外一个队列中

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_57

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_58

四.Fanout Exchange模式

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_59

​Fanout​​ 模式下只要是绑定了Exchange(交换机)的Queue(队列)都会被接受到信息

1.前期准备

注意​:为了测试Fanout 转发模式我们需要把Topic模式用到的类都删除,避免影响到Fanout 的测试,我这的做法是把​​Topic使用到的类@Configuration​​和​​@Component​​注释这样spring就不会加载这个对象

DirectConfig配置类注释上

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_27

TopicConsumer消费者类注释上

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_61

2.Fanout配置编写

没有创建路由关键字因为Fanout交换机必须要,只要绑定该交换机就都会分发数据到队列中

注意​:在Spring中通过​​@Bean​​创建对象时,如果多个bean的类型是一样的我们需要使用​​@Qualifier()​​来指定使用的是那个@Bean,如果​​@Bean(name="cs")​​没有指定name属性那么@Qualifier()里面填写的就是方法的名称,你可以在这个绑定交换机和队列的方法上看到参数有使用这个注解​​@Qualifier()​

/**
* Fanout模式
*/
@Configuration
public class FanoutConfig {


/**
* 创建队列
*/
public static final String QUEUE_FANOUT_ORDER="fanout_order_message";//订单的队列
public static final String QUEUE_FANOUT_WMS="fanout_wms_message";//库存的队列

/**
* 配置交换机
*/
public static final String FANOUT_EXCHANGE="fanout";//topic类型交换机

/**
* 声明队列
* @return
*/
@Bean
public Queue fanoutQueueOrder(){
//持久 - 如果我们声明一个持久队列,则为真(该队列将在服务器重启后继续存在)
return new Queue(QUEUE_FANOUT_ORDER,false);
}
@Bean
public Queue fanoutQueueWms(){
//持久 - 如果我们声明一个持久队列,则为真(该队列将在服务器重启后继续存在)
return new Queue(QUEUE_FANOUT_WMS,false);
}


/**
* 声明交换机
* @return
*/
@Bean
public FanoutExchange FanoutExchange(){
//交换器名称、是否持久化、是否自动删除
return new FanoutExchange(FANOUT_EXCHANGE,true,false);
}

/***
* 队列绑定到交换机上
*/
@Bean
public Binding bindingExchangeOrder(@Qualifier("fanoutQueueWms") Queue queue, FanoutExchange exchange){

return BindingBuilder.bind(queue).to(exchange);
}

/***
* 队列绑定到交换机上
*/
@Bean
public Binding bindingExchangeWms(@Qualifier("fanoutQueueOrder") Queue queue, FanoutExchange exchange){

return BindingBuilder.bind(queue).to(exchange);
}

}

3.创建Fanout接口测试

RabbitMqController创建接口

生产者类不需要改动,我们只要把传人的数据改成FanoutConfig的交换机不需要传递路由关键词添加以下代码到​​RabbitMqController​​类

@ApiOperation(value = "Fanout:订单信息")
@PostMapping("transferOrderFanout")
public ResponseEntity<Void> transferOrderFanout(@ApiParam(value = "数据信息",required = true) @RequestParam String message){
Map map=new HashMap();
map.put("UUID", UUID.randomUUID());
map.put("MESSAGE",message);
map.put("CREATEDATE", DateTime.now());//2021-12-21 10:35:31
//交换机名称 路由关键字 传递的数据
orderProducer.send(FanoutConfig.FANOUT_EXCHANGE,"",map);
return ResponseEntity.noContent().build();
}

4.创建消费者

在Consumer包下创建FanoutConsumer消费者创建2个方法来消费对应的对象信息!

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_62

@Component
public class FanoutConsumer {
private static final Logger logger= LoggerFactory.getLogger(FanoutConsumer.class);

@RabbitListener(queues = {"fanout_order_message"})//队列名称(fanout_order_message)
public void topicOrder(Map message){
System.out.println("fanoutOrder处理信息:"+message.toString());
System.out.println("处理订单完成:"+message.get("MESSAGE"));
}
@RabbitListener(queues = {"fanout_wms_message"})//队列名称(fanout_wms_message)
public void topicWms(Map message){
System.out.println("fanoutWms处理信息:"+message.toString());
System.out.println("处理订单完成:"+message.get("MESSAGE"));
}

}

运行项目查看浏览器RabbitMq的管理界面(​​里面有2个队列是Topic的先不管​​ )只看我们的Fanout的队列

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_63

调用swagger来运行接口测试

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_64

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_65

调用接口可以发现只要是绑定了​​FanoutExchange​​交换机的队列都会收到信息

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_66

5.使用ApiPost请求接口

展示一下Apipost请求swagger的接口来调用队列,这个接口我们只要传递一个message测试和请求方式为Post

请求路径是通过url路径拼接起来的

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_67

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_68

这个就是请求路径

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_69

回到ApiPost上

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_spring_70

可以看出已经调用上接口了,

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_71

五.补充知识点:

关于本次演示代码部分有个点需要补充下以免初学者产生疑问!


由于我在每种模式的配置类中都有创建对应的队列,这样就意味着启动项目就会往Rabbitmq中创建交换机,队列等操作
SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_72
SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_数据_73
这样使用这种方式监听队列的信息是没问题的!SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_rabbitmq_74


但是然后你​​没有创建队列​​信息使用这种只填写队列名称来监听是不可行的!需要使用以下方式来解决这个问题

@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "topic_order_message",//队列名称
durable = "true"//是否持久保存
),
exchange = @Exchange(value = "topic_exchange",//交换机名称
ignoreDeclarationExceptions = "true",//忽略声明异常如果有这个交换机了就用mq里面的
type = ExchangeTypes.TOPIC, //交换机类型:direct,fanout,topic 等
durable = "true"//默认就是true 可以省略这个属性
),
key = {"direct.order.routing"}//路由关键字:routing key
))
public void topicOrder(Map message){
System.out.println("topicOrder处理信息:"+message.toString());
System.out.println("处理订单完成:"+message.get("MESSAGE"));
}

SpringBoot整合Rabbitmq(入门教程)分别对Direct,Topic,Fanout模式进行代码测试_java_75