介绍
rabbitmq有六种工作模式。我们使用springboot整合实现rabbitmq的六种工作模式,并在其中谈及如何调用ack。
准备工作
导入springboot的rabbitmq的场景,还有一个web场景
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
然后设置yaml里面的配置文件,
server:
port: 5672
spring:
rabbitmq:
host: 192.168.80.88 #mq服务器ip,默认为localhost
port: 5672 #mq服务器port,默认为5672
username: guest #mq服务器username,默认为gust
password: guest #mq服务器password,默认为guest
实现
简单模式
简单模式也可以称为hello-world模式,我们使用默认的交换机,只需要声明队列,消费者和生产者
先创建队列
@Bean
public Queue Queue() {
return new Queue("hello");
}
然后创建生产者
@Controller
public class HelloSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hello " + new Date();
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("hello", context);
}
}
再创建消费者
@Component
@RabbitListener(queues = "hello")
public class HelloReceiver {
@RabbitHandler
public void process(String hello) {
System.out.println("Receiver : " + hello);
}
}
再写一个测试用例看看
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqApplicationTests {
@Autowired
private HelloSender helloSender;
@Test
public void hello() throws Exception {
helloSender.send();
}
}
工作模式
工作模式就是在简单模式上添加多个消费者,在此我们使用的是默认交换机
我们先创建一个队列
@Bean
public Queue Queue2() {
return new Queue("neo");
}
再创建一个消息生产者
@Controller
public class NeoSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send(int i) {
String context = "spirng boot neo queue"+" ****** "+i;
System.out.println("Sender1 : " + context);
this.rabbitTemplate.convertAndSend("neo", context);
}
}
再创建两个消息的消费者
@Component
@RabbitListener(queues = "neo")
public class NeoReceiver1 {
@RabbitHandler
public void process(String neo) {
System.out.println("Receiver 1: " + neo);
}
}
@Component
@RabbitListener(queues = "neo")
public class NeoReceiver2 {
@RabbitHandler
public void process(String neo) {
System.out.println("Receiver 2: " + neo);
}
}
我们写一个测试用例
@Test
public void oneToMany() throws Exception {
for (int i=0;i<1000;i++){
neoSender.send(i);
}
}
发布订阅模式
在发布订阅模式下,生产者将消息发送到X交换机,然后由交换机发送给两个队列,两个消费者各自监听一个队列,来消费消息。
这种方式实现同一个消息被多个消费者消费。工作模式是同一个消息只能有一个消费者。
我们新建三个队列
@Bean
public Queue AMessage() {
return new Queue("fanout.A");
}
@Bean
public Queue BMessage() {
return new Queue("fanout.B");
}
@Bean
public Queue CMessage() {
return new Queue("fanout.C");
}
再新建一个交换机
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}
再把这些队列绑定到交换机上去
@Bean
Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(CMessage).to(fanoutExchange);
}
基本的配置完成后,再新建一个消息生产者
@Component
public class FanoutSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hi, fanout msg ";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("fanoutExchange","", context);
}
}
同样的,我们再新建三个消息消费者
@Component
@RabbitListener(queues = "fanout.A")
public class FanoutReceiveA {
@RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver A : " + message);
}
}
@Component
@RabbitListener(queues = "fanout.B")
public class FanoutReceiverB {
@RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver B: " + message);
}
}
@Component
@RabbitListener(queues = "fanout.C")
public class FanoutReceiverC {
@RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver C: " + message);
}
}
三个消费者分别监听3个队列的内容,然后新建一个测试用例:
@RunWith(SpringRunner.class)
@SpringBootTest
public class FanoutTest {
@Autowired
private FanoutSender fanoutSender;
@Test
public void setFanoutSender(){
fanoutSender.send();
}
}
路由模式
需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配,这是一个完整的匹配。
路由模式的代码和主题模式放在一起
主题模式
发送端不只按固定的routing key发送消息,而是按字符串匹配发送,接收端同样如此
符号#匹配一个或多个词,符号*匹配不多不少一个词。
新建两个队列
final static String message = "topic.A";
final static String messages = "topic.B";
@Bean
public Queue queueMessage() {
return new Queue(TopicRabbitConfig.message);
}
@Bean
public Queue queueMessages() {
return new Queue(TopicRabbitConfig.messages);
}
新建一个交换机
@Bean
TopicExchange exchange() {
return new TopicExchange("topicExchange");
}
绑定队列到交换机上,路由模式,需要完整匹配topic.message,才能接受
@Bean
Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
topic模式,前缀匹配到topic.即可接受
@Component
public class TopicSend {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hi, i am message all";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.1", context);
}
public void send1() {
String context = "hi, i am message 1";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
}
public void send2() {
String context = "hi, i am messages 2";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
}
}
我们新建三个消息生产者
send的key是topic.1 send1的key是topic.message,send2的key是topic.messages
所以理论上send会被两个队列消费,1.2都应该只有一个队列消费
我们再新建两个消费者
@Component
@RabbitListener(queues = "topic.A")
public class TopicReceiver {
@RabbitHandler
public void process(String message) {
System.out.println("Topic Receiver1 : " + message);
}
}
@Component
@RabbitListener(queues = "topic.B")
public class TopicReceiver2 {
@RabbitHandler
public void process(String message) {
System.out.println("Topic Receiver2 : " + message);
}
}
写三个测试用例
@RunWith(SpringRunner.class)
@SpringBootTest
public class TopicTest {
@Autowired
private TopicSend sender;
@Test
public void topic() throws Exception {
sender.send();
}
@Test
public void topic1() throws Exception {
sender.send1();
}
@Test
public void topic2() throws Exception {
sender.send2();
}
}