SpringBoot集成RabbitMQ
Docker安装RabbitMQ
下载带有管理界面的RabbitMQ Docker镜像
docker pull rabbitmq:3.7.7-management
然后创建并运行RabbitMQ容器
docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.7.7-management
docker run -d --hostname rabbitmqhost --name rabbitmq3.6 --restart always -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.6.15-management
-d:后台运行
--hostname:设置容器的主机名
--name:容器命名
--restart always:开机启动
-p:端口号映射,前面是宿主机端口,后面是容器端口
-v:挂载宿主机目录到容器目录
-e:设置容器环境变量
游览器访问:http://服务器ip地址:15672
输入启动容器是设置的用户名密码登录就进去管理页面啦
先关概念
交换机
交换机的主要功能是接收消息并转发到绑定的队列,交换机自身不存储消息,当启动ack模式后,交换机找不到指定的队列会返回错误。交换机类型有Direct、topic、 Headers、Fanout四种类型
Direct Exchange交换机
Direct Exchange 是 RabbitMQ 默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。发送消息是设置一个routing_key,当routing_key匹配时才将消息传送到绑定的队列中。
Topic Exchange交换机
Topic Exchange跟Direct Exchange类似,在匹配上增加了模式概念,从以点分开的routing_key形式中,可用使用2中统配符:*表示一个单词,#表示0个或者多个单词
Headers Exchange交换机
Headers Exchange是一个自定义匹配规则的类型,在交换器与队列绑定时,会制定一组键值对规则,发送消息时也会制定一组规则,当这些键值对有一对或者多对匹配时,消息会传送到对应的队列中。
Fanout Exchange交换机
Fanout Exchange用的是消息广播模式,设置路由建无效,它会把消息传送给交换机下的所有队列。
SpringBoot集成RabbitMQ
简单使用
创建一个主工程:spring-boot-rabbitmq,添加如下内容:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>2.1.5.RELEASE</version>-->
<version>1.5.20.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-boot.version>1.5.20.RELEASE</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在spring-boot-rabbitmq主工程中创建一个RabbitMQ配置的Maven module:rabbitmq-config
添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
创建一个配置类:RabbitConfig.java,添加如下内容
@Configuration
public class RabbitConfig {
//创建一个hello-queue消息队列
@Bean
public Queue helloQueue() {
return new Queue("hello-queue");
}
}
在spring-boot-rabbitmq主工程中创建一个消息发送方的SpringBoot module:rabbitmq-sender
在pom文件中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alyshen</groupId>
<artifactId>rabbitmq-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
在resource目录下创建配置文件:application.properties,添加如下内容:
############### 服务配置 #############
server.port=9000
spring.application.name=rabbitmq-sender
############### RabbitMQ配置 ##############
spring.rabbitmq.host=192.168.86.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
创建工程启动类:RabbitmqSenderApplication.java,添加如下内容:
@SpringBootApplication
public class RabbitmqSenderApplication {
public static void main(String[] args) {
SpringApplication.run(RabbitmqSenderApplication.class,args);
}
}
创建一个消息生产者:HelloQueueSender.java
@Component
public class HelloQueueSender {
@Autowired
private AmqpTemplate amqpTemplate;
public void send(String msg) {
String context = msg + ",sender date:" + new Date();
System.out.println("Sender to hello-queue: " + context);
this.amqpTemplate.convertAndSend("hello-queue", context);//使用hello-queue队列
}
}
创建一个HelloSenderController供浏览器发送消息,添加如下内容:
@RestController
public class HelloSenderController {
@Autowired
private HelloQueueSender helloQueueSender;
@RequestMapping(value = "/senderMessage")
public String senderMessage(@PathParam(value = "msg") String msg){
helloQueueSender.send(msg);
return "sender ok...";
}
}
运行项目rabbitmq-sender,访问:
http://localhost:9000/senderMessage?msg=消息内容
这时消息内容保存到rabbitmq队列中待消息消费方获取
创建一个消息接收方的SpringBoot工程:rabbitmq-receiver
在pom文件中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alyshen</groupId>
<artifactId>rabbitmq-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
在resource目录下创建配置文件:application.properties,添加如下内容:
############### 服务配置 #############
server.port=9100
spring.application.name=rabbitmq-receiver
############### RabbitMQ配置 ##############
spring.rabbitmq.host=192.168.86.101
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
创建工程启动类:RabbitmqReceiverApplication.java
添加如下内容:
@SpringBootApplication
public class RabbitmqReceiverApplication {
public static void main(String[] args) {
SpringApplication.run(RabbitmqReceiverApplication.class,args);
}
}
在rabbitmq-receiver的pom文件中加入rabbitmq-config工程依赖
创建一个消息处理者:HelloQueueReceiver.java
@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver {
@RabbitHandler
public void process(String hello){
System.out.println("Receiver:" + hello);
}
}
启动工程rabbitmq-receiver,输出内容:
Receiver:消息内容,……
即获取到消息内容
多对多使用
一对多使用
将rabbitmq-sender中的HelloSenderController内容修改成如下所示:
@RestController
public class HelloSenderController {
@Autowired
private HelloQueueSender helloQueueSender;
@RequestMapping(value = "/senderMessage")
public String senderMessage(@PathParam(value = "msg") String msg) {
for (int i = 1; i <= 20; i++) {
helloQueueSender.send(i + "," + msg);
}
return "sender ok...";
}
}
把rabbitmq-receiver中的HelloQueueReceiver.java复制一份,分别改成如下:
HelloQueueReceiver.java
@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver {
@RabbitHandler
public void process(String msg) {
System.out.println("Receiver 1:" + msg);
}
}
HelloQueueReceiver2.java
@Component
@RabbitListener(queues = "hello-queue")
public class HelloQueueReceiver2 {
@RabbitHandler
public void process(String msg){
System.out.println("Receiver 2:" + msg);
}
}
将rabbitmq-sender和rabbitmq-receiver运行起来
访问http://localhost:9000/senderMessage?msg=消息内容
rabbitmq-sender控制台输出:
Sender to hello-queue: 1,消息内容,……
Sender to hello-queue: 2,消息内容,……
Sender to hello-queue: 3,消息内容,……
Sender to hello-queue: 4,消息内容,……
Sender to hello-queue: 5,消息内容,……
Sender to hello-queue: 6,消息内容,……
Sender to hello-queue: 7,消息内容,……
Sender to hello-queue: 8,消息内容,……
Sender to hello-queue: 9,消息内容,……
Sender to hello-queue: 10,消息内容,……
Sender to hello-queue: 11,消息内容,……
Sender to hello-queue: 12,消息内容,……
Sender to hello-queue: 13,消息内容,……
Sender to hello-queue: 14,消息内容,……
Sender to hello-queue: 15,消息内容,……
Sender to hello-queue: 16,消息内容,……
Sender to hello-queue: 17,消息内容,……
Sender to hello-queue: 18,消息内容,……
Sender to hello-queue: 19,消息内容,……
Sender to hello-queue: 20,消息内容,……
rabbitmq-receiver控制台输出:
Receiver 1:1,消息内容,……
Receiver 2:2,消息内容,……
Receiver 1:3,消息内容,……
Receiver 2:4,消息内容,……
Receiver 1:5,消息内容,……
Receiver 2:6,消息内容,……
Receiver 1:7,消息内容,……
Receiver 2:8,消息内容,……
Receiver 1:9,消息内容,……
Receiver 2:10,消息内容,……
Receiver 1:11,消息内容,……
Receiver 2:12,消息内容,……
Receiver 1:13,消息内容,……
Receiver 2:14,消息内容,……
Receiver 1:15,消息内容,……
Receiver 2:16,消息内容,……
Receiver 1:17,消息内容,……
Receiver 2:18,消息内容,……
Receiver 1:19,消息内容,……
Receiver 2:20,消息内容,……
可以看出消息消费方是轮流有序的获取消息的
多对多使用
将rabbitmq-sender中的HelloQueueSender复制一份创建HelloQueueSender2,就类名不一样,其他都一样
改造一下rabbitmq-sender工程中的HelloSenderController,改成入下:
@RestController
public class HelloSenderController {
@Autowired
private HelloQueueSender helloQueueSender;
@Autowired
private HelloQueueSender2 helloQueueSender2;
@RequestMapping(value = "/senderMessage")
public String senderMessage(@PathParam(value = "msg") String msg) {
for (int i = 1; i <= 20; i++) {
helloQueueSender.send("sender1 " + i + "." + msg);
helloQueueSender2.send("sender2 " + i + "." + msg);
}
return "sender ok...";
}
}
运行rabbitmq-sender
访问http://localhost:9000/senderMessage?msg=消息内容
rabbitmq-sender控制台输出
Sender to hello-queue: sender1 1.消息内容,……
Sender to hello-queue: sender2 1.消息内容,……
Sender to hello-queue: sender1 2.消息内容,……
Sender to hello-queue: sender2 2.消息内容,……
Sender to hello-queue: sender1 3.消息内容,……
Sender to hello-queue: sender2 3.消息内容,……
Sender to hello-queue: sender1 4.消息内容,……
Sender to hello-queue: sender2 4.消息内容,……
Sender to hello-queue: sender1 5.消息内容,……
Sender to hello-queue: sender2 5.消息内容,……
Sender to hello-queue: sender1 6.消息内容,……
Sender to hello-queue: sender2 6.消息内容,……
Sender to hello-queue: sender1 7.消息内容,……
Sender to hello-queue: sender2 7.消息内容,……
Sender to hello-queue: sender1 8.消息内容,……
Sender to hello-queue: sender2 8.消息内容,……
Sender to hello-queue: sender1 9.消息内容,……
Sender to hello-queue: sender2 9.消息内容,……
Sender to hello-queue: sender1 10.消息内容,……
Sender to hello-queue: sender2 10.消息内容,……
Sender to hello-queue: sender1 11.消息内容,……
Sender to hello-queue: sender2 11.消息内容,……
Sender to hello-queue: sender1 12.消息内容,……
Sender to hello-queue: sender2 12.消息内容,……
Sender to hello-queue: sender1 13.消息内容,……
……
rabbitmq-receiver的控制台输出:
Receiver 1:sender1 1.消息内容,……
Receiver 2:sender2 1.消息内容,……
Receiver 1:sender1 2.消息内容,……
Receiver 2:sender2 2.消息内容,……
Receiver 1:sender1 3.消息内容,……
Receiver 2:sender2 3.消息内容,……
Receiver 1:sender1 4.消息内容,……
Receiver 2:sender2 4.消息内容,……
Receiver 1:sender1 5.消息内容,……
Receiver 2:sender2 5.消息内容,……
Receiver 1:sender1 6.消息内容,……
Receiver 2:sender2 6.消息内容,……
Receiver 1:sender1 7.消息内容,……
Receiver 2:sender2 7.消息内容,……
Receiver 1:sender1 8.消息内容,……
Receiver 2:sender2 8.消息内容,……
Receiver 1:sender1 9.消息内容,……
Receiver 2:sender2 9.消息内容,……
Receiver 2:sender2 10.消息内容,……
Receiver 1:sender1 10.消息内容,……
Receiver 1:sender1 11.消息内容,……
Receiver 2:sender2 11.消息内容,……
Receiver 1:sender1 12.消息内容,……
Receiver 2:sender2 12.消息内容,……
Receiver 2:sender1 13.消息内容,……
Receiver 1:sender2 13.消息内容,……
可以看出在多对多情况下消息依然是有序取出的
高级使用
对象的使用
在spring-boot-rabbitmq主工程中创建一个model module:rabbitmq-model
添加一个model:User
内容如下:
public class User implements Serializable {
public static final Long serialVersionUID = 1L;
private String username;
private String passwd;
private int age;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", passwd='" + passwd + '\'' +
", age=" + age +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
分别在rabbitmq-sender和rabbitmq-receiver工程中加入rabbitmq-model依赖
<dependency>
<groupId>com.alyshen</groupId>
<artifactId>rabbitmq-model</artifactId>
<version>${project.version}</version>
</dependency>
在rabbitmq-config工程中的配置类RabbitmqConfig.java加入方法:
//创建一个user-queue消息队列
@Bean
public Queue userQueue() {
return new Queue("user-queue");
}
在rabbitmq-sender工程中参加一个生产方:UserSender.java,内容如下:
@Component
public class UserSender {
@Autowired
private AmqpTemplate amqpTemplate;
public void senderUser(User user) {
System.out.println("Sender to user-queue: " + user);
amqpTemplate.convertAndSend("user-queue",user);
}
}
在添加一个Controller:UserSenderController.java,内容如下:
@RestController
public class UserSenderController {
@Autowired
UserSender userSender;
@RequestMapping(value = "/sendUser")
public String senduser() {
User user = new User();
user.setUsername("zhangshan");
user.setPasswd("zzzpwd");
user.setAge(20);
userSender.senderUser(user);
return "sender user ok ...";
}
}
运行rabbitmq-sender工程,浏览器访问:http://localhost:9000/sendUser,控制台输出:
Sender to user-queue: User{username='zhangshan', passwd='zzzpwd', age=20}
一个username为zhangshan的User就加入了user-queue队列中
现在rabbitmq-receiver工程中创建一个User消息接收方:UserReceiver.java,内容如下:
@Component
public class UserReceiver {
// @RabbitHandler
@RabbitListener(queues = "user-queue")
public void process(User user) {
System.out.println("Receiver user:" + user);
}
}
运行rabbitmq-receiver工程,控制台输出:
Receiver user:User{username='zhangshan', passwd='zzzpwd', age=20}
User信息接收成功
Topic Exchange的使用
在rabbitmq-config工程中创建配置类TopicRabbitConfig.java,内容如下:
@Configuration
public class TopicRabbitConfig {
final static String message = "topic.message";
final static String messages = "topic.messages";
@Bean
public Queue queueMessage() {
return new Queue(TopicRabbitConfig.message);
}
@Bean
public Queue queueMessages() {
return new Queue(TopicRabbitConfig.messages);
}
/**
* @Title exchange
* @Description 创建个Topic交换机
*/
@Bean
TopicExchange exchange() {
return new TopicExchange("topicExchange");
}
/**
* @Title bindingExchangeMessage
* @Description 交换机和路由建绑定
*/
@Bean
Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
在rabbitmq-sender工程中添加topic消息发送方:TopicSender.java,添加如下内容:
@Component
public class TopicSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void sender() {
String context = "消息1...";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.xxx", context);
}
public void sender2() {
String context = "消息2...";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
}
public void sender3() {
String context = "消息3...";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
}
}
再创建一个TopicSenderController,添加如下内容:
@RestController
public class TopicSenderController {
@Autowired
private TopicSender topicSender;
@RequestMapping(value = "/topic")
public String topic() {
topicSender.sender();
return "sender ok...";
}
@RequestMapping(value = "/topic2")
public String topic2() {
topicSender.sender2();
return "sender ok...";
}
@RequestMapping(value = "/topic3")
public String topic3() {
topicSender.sender3();
return "sender ok...";
}
}
在rabbitmq-receiver工程中创建topic消息接收端:TopicReceiver1.java,添加如下内容:
@Component
public class TopicReceiver1 {
// @RabbitHandler
@RabbitListener(queues = "topic.message")
public void process(String message) {
System.out.println("Topic Receiver 1:" + message);
}
}
在创建一个topic消息接收端:TopicReceiver2.java,添加如下内容:
@Component
public class TopicReceiver2 {
// @RabbitHandler
@RabbitListener(queues = "topic.messages")
public void process(String message) {
System.out.println("Topic Receiver 2:" + message);
}
}
运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/topic
发现只有Receiver 2接收到消息1,说明topic.xxx匹配的是topic.#这个规则
浏览器访问:http://localhost:9000/topic2
发现Receiver 1和Receiver 2都接收到了消息2,说明topic.message匹配的是topic.message和topic.#这两个规则
浏览器访问:http://localhost:9000/topic3
发现只有Receiver 2都接收到了消息3,说明topic.messages匹配的是topic.#这个规则
fanout Exchange的使用
在rabbitmq-config工程中创建配置类FanoutRabbitConfig.java,添加如下内容:
@Configuration
public class FanoutRabbitConfig {
//创建队列a
@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");
}
// 创建Fanout 交换机
@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);
}
}
在rabbitmq-sender工程中添加fanout消息发送方:FanoutSender.java,添加如下内容:
@Component
public class FanoutSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void sender() {
String context = "fanout 消息内容...";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("fanoutExchange", "", context);
}
}
再创建一个FanoutSenderController,添加如下内容:
@RestController
public class FanoutSenderController {
@Autowired
private FanoutSender fanoutSender;
@RequestMapping(value = "/fanout")
public String topic() {
fanoutSender.sender();
return "sender ok...";
}
}
在rabbitmq-receiver工程中创建fanout消息接收端:FanoutReceiver.java,添加如下内容:
@Component
public class FanoutReceiver {
// @RabbitHandler
@RabbitListener(queues = "fanout.A")
public void process(String message) {
System.out.println("fanout Receiver A:" + message);
}
@RabbitListener(queues = "fanout.B")
public void process2(String message) {
System.out.println("fanout Receiver B:" + message);
}
@RabbitListener(queues = "fanout.C")
public void process3(String message) {
System.out.println("fanout Receiver C:" + message);
}
}
运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/fanout
在rabbitmq-receiver工程的控制台下输出:
fanout Receiver B:fanout 消息内容...
fanout Receiver C:fanout 消息内容...
fanout Receiver A:fanout 消息内容...
说明绑定到fanout交换机上的队列都接收到了消息