RabbitMQ
文章目录
安装
这里使用docker安装,简单方便。
docker pull rabbitmq:3.8.10-management
注意我们要下载management版本的,其他版本是没有web端管理界面的;
我们运行一个容器:docker run -d --name myrabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.8.10-management
其中15672是我们管理web端的端口。
介绍
浏览器输入ip:15672
即可出现rabbitmq的web端管理界面。
默认的管理员用户密码都是guest
,我们也可以新建用户,为其分配Virtual Host。
交换机exchange一般都是一个项目用一个。
我们看Rabbitmq官网列出了其中模型,其中消息队列主要涉及前5种。
HelloWorld
这是最简单的一种模型,生产者把消息放到队列里面,然后消费者从队列里面拿出来。
Work模型
这个其实就是有好多的消费者,消费者们从同一个里面队列里面拿消息。如果有多条消息,默认是采用轮询的,即消费者们一个一个拿消息。
fanout模型
生产者把消息放到交换机里,然后每一个消费者分配一个队列,交换机把消息发到每一个队列中。这是一种广播模型,我们需要制定交换机的类型为fanout。
Routing模型
在fanout的基础上,根据routeKey使得某一部分队列拿到消息,某一部分拿不到。
Topic模型
在route的基础上,加入了通配符配置key,key表示为a.b.c
这种按点分割单词的形式,*
可匹配任意一个单词,#
可匹配任意个单词。
SpringBoot中使用RabbitMQ
准备
这里就简单测试一下五种模型。
首先我们新建一个用户ems
,并给他添加一个虚拟主机/ems
。
新建一个springboot项目,添加Spring for RabbitMQ
模块。
或者你在pom中添加坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
配置
在yml中简单配一下:
spring:
application:
name: springboot-rabbitmq
rabbitmq:
host: 不给看
port: 5672
username: ems
password: 123
virtual-host: /ems
生产者
我们这里写一个测试类,看下5中模型的生产者是怎么写的:
package com.ljj;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = SpringbootRabbitmqApplication.class)
@RunWith(SpringRunner.class)
public class TestRabbitmq {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* hello world模型
*/
@Test
public void testHelloWorld() {
rabbitTemplate.convertAndSend("hello","Hello RabbitMQ");
}
/**
* work模型
*/
@Test
public void testWork() {
for (int i = 0; i < 10; i++) {
rabbitTemplate.convertAndSend("work","work模型");
}
}
/**
* fanout模型 广播
*/
@Test
public void testFanout() {
rabbitTemplate.convertAndSend("logs","","fanout模型");
}
/**
* route模型
*/
@Test
public void testRoute() {
rabbitTemplate.convertAndSend("directs","info","route模型");
}
/**
* topic模型
*/
@Test
public void testTopic() {
rabbitTemplate.convertAndSend("topics","a.b.c","topic模型");
}
}
我们需要注入RabbitTemplate
,然后使用它的convertAndSend
方法。
可以看到无论是哪一种模型,都是采用这个方法发消息的。
前两种模型因为不涉及交换机,所以只用两个参数:第一个参数是routeKey,用于找到队列,第二个参数是消息内容。
而后三种模型需要交换机,所以第一个参数是交换机的名称(如果没有会新建),第二个参数是routeKey,fanout模型是广播,全部发送,所以routeKey填空串即可。
消费者
helloworld
package com.ljj.mq.consumers;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
//默认是持久化,非独占,非自动删除
@RabbitListener(queuesToDeclare = @Queue(value = "hello",durable = "true",autoDelete = "false"))
public class HelloCustomer {
@RabbitHandler
public void dealMessage(String message) {
System.out.println("message:" + message);
}
}
使用@RabbitListener
注解和@RabbitHandler
注解配合使用完成消费。
work
package com.ljj.mq.consumers;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkCustomer {
//消费者1
@RabbitListener(queuesToDeclare = @Queue("work"))
public void dealMessage1(String message) {
System.out.println("message1:"+message);
}
//消费者2
@RabbitListener(queuesToDeclare = @Queue("work"))
public void dealMessage2(String message) {
System.out.println("message2:"+message);
}
}
没错@RabbitLister
注解可以直接作用在方法上,queuesToDeclare
表示如果没有这个队列就新建。
这里@Queue
中指定的队列名即为routeKey。
fanout
package com.ljj.mq.consumers;
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.Component;
@Component
public class FanoutCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue, //不指定Queue的value表示创建临时队列
exchange = @Exchange(value = "logs",type = "fanout")//指定交换机名称和类型
)
})
public void dealMessage1(String message) {
System.out.println("message1:"+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs",type = "fanout")
)
})
public void dealMessage2(String message) {
System.out.println("message2:"+message);
}
}
这个麻烦一点,其实也就是多配置了交换机的名称和类型。
routing
package com.ljj.mq.consumers;
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.Component;
@Component
public class RouteCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange("directs"), //type默认即为direct
key = {"info","error"}
)
})
public void dealMessage1(String message) {
System.out.println("message1:"+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange("directs"), //type默认即为direct
key = {"error"}
)
})
public void dealMessage2(String message) {
System.out.println("message2:"+message);
}
}
同fanout,多配一个key,使得消息只发送到一部分queue中。
topic
package com.ljj.mq.consumers;
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.Component;
@Component
public class TopicCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "topics",type = "topic"),
key = {"a.*.c"}
)
})
public void dealMessage1(String message) {
System.out.println("message1:"+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "topics",type = "topic"),
key = {"#.c"}
)
})
public void dealMessage2(String message) {
System.out.println("message2:"+message);
}
}
配置key时可以加入通配符。