参考:https://blog.csdn.net/qq_35387940/article/details/100514134
一、目录结构
二、消息生产者
2.1 生产者目录结构
2.2 pom.xml文件
引入mq的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
2.3 application.yml文件
server:
port: 8021
spring:
application:
name: rabbitmq-provider
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirm-type: correlated
2.4 直联交换机配置 DirectRabbitConfig.java
package com.vv.producer.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 直联交换机的配置
*/
@Configuration
public class DirectRabbitConfig {
//队列 起名:TestDirectQueue
@Bean
public Queue TestDirectQueue(){
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
// return new Queue("TestDirectQueue",true,true,false);
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue("TestDirectQueue1",true);
}
//Direct交换机 起名:TestDirectExchange
@Bean
DirectExchange TestDirectExchange(){
return new DirectExchange("TestDirectExchange1",true,false);
}
//绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting
@Bean
Binding bindingDirect(){
return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting1");
}
@Bean
DirectExchange lonelyDirectExchange(){
return new DirectExchange("lonelyDirectExchange");
}
}
2.5 生产者Controller
package com.vv.producer.controller;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
public class SendMessageController {
@Autowired
RabbitTemplate rabbitTemplate;
@GetMapping("/sendDirectMessage")
public String sendDirectMessage(){
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "test message, hello!";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String,Object> map=new HashMap<>();
map.put("messageId",messageId);
map.put("messageData",messageData);
map.put("createTime",createTime);
rabbitTemplate.convertAndSend("TestDirectExchange1","TestDirectRouting1",map);
return "OK";
}
@GetMapping("/sendtopicMessage1")
public String sendTopicMessage1(){
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: M A N ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> manMap = new HashMap<>();
manMap.put("messageId", messageId);
manMap.put("messageData", messageData);
manMap.put("createTime", createTime);
rabbitTemplate.convertAndSend("topicExchange", "topic.man", manMap);
return "ok:Man";
}
@GetMapping("/sendtopicMessage2")
public String sendTopicMessage2(){
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: woman is all ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> womanMap = new HashMap<>();
womanMap.put("messageId", messageId);
womanMap.put("messageData", messageData);
womanMap.put("createTime", createTime);
rabbitTemplate.convertAndSend("topicExchange", "topic.woman", womanMap);
return "ok:Woman";
}
}
三、运行rabbitmq-provider(生产者)项目
3.1 此时需要确保rabbitMQ本地服务已正常启动
3.2 访问生产者API,生成生产者的消息(访问三次)
http://localhost:8021/sendDirectMessage
3.2 查看MQ的消息
四、消息消费者
4.1 pom文件引入mq依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
4.2 配置application.yml文件
server:
port: 8022
spring:
application:
name: rabbitmq-consumer
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirm-type: correlated
4.3 配置MQ的消息监听器
package com.vv.consumer.receiver;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* mq消息监听器
*/
@Component
@RabbitListener(queues = "TestDirectQueue1") //监听的队列名称 TestDirectQueue
public class DirectReceiver {
@RabbitHandler
public void process(Map message){
System.out.println("第一个消费者,接收数 :" + message.toString());
}
}
4.4 启动消费者项目
根据控制台打印可以看出,启动消费者项目后,消费者会对之前存在的消息进行消费(但都是消费者1进行消费,此处尚不明白为什么),再次调用生产者的链接时,消费者1、2、3会轮询消费消息
五、创建主题交换机
5.1 生产者创建主题交换机配置
package com.vv.producer.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 主题交换机
*/
@Configuration
public class TopicRabbitConfig {
//绑定键
public final static String man = "topic.man";
public final static String woman = "topic.woman";
public final static String all = "topic.#";
@Bean
public Queue firstQueue(){
return new Queue(TopicRabbitConfig.man);
}
@Bean
public Queue secondQueue(){
return new Queue(TopicRabbitConfig.woman);
}
@Bean
TopicExchange exchange(){
return new TopicExchange("topicExchange");
}
//将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
//这样只要是消息携带的路由键是topic.man,才会分发到该队列
@Bean
Binding bindingExchangeMessage(){
return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
}
//将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
// 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
@Bean
Binding bindingExchangeMessage2(){
return BindingBuilder.bind(secondQueue()).to(exchange()).with(all);
}
}
对应的controller中上面已经有调用的方法了,此处不再展示
5.2 消费者创建topic.man消息监听器
package com.vv.consumer.receiver;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@RabbitListener(queues = "topic.man")
public class TopicManReceiver {
@RabbitHandler
public void receiveMan(Map message){
System.out.println("主题订阅TopicManReceiver消费者接收消息 :" + message.toString());
}
}
5.3 消费者创建topic.woman消息监听器
package com.vv.consumer.receiver;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@RabbitListener(queues = "topic.woman")
public class TopicWomanReceiver {
@RabbitHandler
public void receiveMan(Map message){
System.out.println("主题订阅TopicWomanReceiver消费者接收消息 :" + message.toString());
}
}
5.4 启动生产者和消费者项目
5.5 创建topic.man消息:同时被TopicManReceiver和TopicWomanReceiver监听
http://localhost:8021/sendtopicMessage1
以上地址被访问了三次,控制台输出如下信息:同时被TopicManReceiver和TopicWomanReceiver监听器监听到,因为发送消息的路由绑定的是topic.man,故同时被两个队列接收
5.6 创建topic.woman消息:只被TopicWomanReceiver监听
http://localhost:8021/sendtopicMessage2
以上地址被访问三此,只路由到了队列2中
以上先记录了RabbitMQ的直联模式和主题模式,后续将继续补充扇形交换机