消息中间件 —— 简介
RabbitMQ —— 介绍
RabbitMQ —— 下载、安装
RabbitMQ —— 工作模式
RabbitMQ —— 简单队列
RabbitMQ —— Round-robin 轮询分发
关于怎么创建 Maven 工程这里就不详细介绍了,创建好的工程如下:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbit-testartifactId>
<scope>testscope>
dependency>
dependencies>
# 启动服务端口
server.port=8081
# 服务名称
spring.application.name=test-rabbitmq-producer
# RabbitMQ 配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
新建一个 config 包,在该包下新建一个配置类,如下:
package com.java.rabbitmq.producer.config;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Woo_home
* @create 2020/5/27 14:09
*/
@Configuration
public class RabbitMQConfig {
// 声明交换机
@Bean
public DirectExchange directExchange() {
return new DirectExchange("EmailExchange");
}
}
package com.java.rabbitmq.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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @author Woo_home
* @create 2020/5/27 14:30
*/
@RestController
public class AMQPController {
// 注入 RabbitTemplate 模板
@Autowired
public RabbitTemplate rabbitTemplate;
@GetMapping("/direct")
public String sendEmail(@RequestParam Map<String, Object> param) {
// 获取参数
String msg = param.get("msg").toString();
// 发送消息,绑定的交换机名称为 EmailExchange,路由为 EmailRouting
rabbitTemplate.convertAndSend("EmailExchange", "EmailRouting", msg);
return "OK";
}
}
package com.java.rabbitmq.producer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
依赖跟上面是一样的,直接复制即可
# 启动服务端口
server.port=8082
# 服务名称
spring.application.name=test-rabbitmq-producer
# RabbitMQ 配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
package com.java.rabbitmq.consumer.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;
/**
* @author Woo_home
* @create 2020/5/27 14:09
*/
@Configuration
public class RabbitMQConfig {
// 声明交换机
@Bean
public DirectExchange emailExchange() {
// 这里的交换机要与生产者的交换机名称一致
return new DirectExchange("EmailExchange");
}
// 声明队列
@Bean
public Queue emailQueue() {
// 队列名称
return new Queue("EmailQueue");
}
// 绑定交换机和队列
@Bean
public Binding bindEmail() {
return BindingBuilder.bind(emailQueue())
// 绑定交换机
.to(emailExchange())
// 和路由
.with("EmailRouting");
}
}
接下来就可以编写业务代码了,其实这个业务代码只是简单接收一下生产者发送的消息即可,代码如下:
package com.java.rabbitmq.consumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author Woo_home
* @create 2020/5/27 14:49
*/
@Component
public class EmailService {
// 监听队列名称为 EmailQueue 的队列
@RabbitListener(queues = "EmailQueue")
public void receive(String msg) {
// 打印消息
System.out.println("收到的消息 " + msg);
}
}
在测试之前可以先把 RabbitMQ 的数据都先清除先,以免混淆,清除 RabbitMQ 数据的命令如下:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
启动消息生产者
访问 http://localhost:8081/direct?msg=2222 如果返回 OK,那么就可以了
刷新一下 Exchange 页面
但是点击 Exchange 进去的时候发现还没有绑定任何东西
这是因为我没还没有启动消息消费者,这里启动一下消息消费者
刷新一下 Queue 界面 http://localhost:15672/#/queues,这个时候就有了一个队列
这个时候点击 Connection 选项就会出现两个连接
而且此时的交换机已经绑定了我们的队列
再次刷新 http://localhost:8081/direct?msg=2222 页面时
消费者的控制台就会输出消息
package com.java.rabbitmq.producer.config;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Woo_home
* @create 2020/5/28 21:08
*/
@Configuration
public class BlogConfig {
// 声明交换机
@Bean
public TopicExchange blogExchange() {
return new TopicExchange("BlogExchange");
}
}
package com.java.rabbitmq.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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @author Woo_home
* @create 2020/5/27 14:30
*/
@RestController
public class AMQPController {
// 注入 RabbitTemplate 模板
@Autowired
public RabbitTemplate rabbitTemplate;
@GetMapping("/direct")
public String sendEmail(@RequestParam Map<String, Object> param) {
// 获取参数
String msg = param.get("msg").toString();
// 发送消息
rabbitTemplate.convertAndSend("EmailExchange", "EmailRouting", msg);
return "OK";
}
@GetMapping("/topic")
public String sendBlog(@RequestParam Map<String, Object> param) {
String msg = param.get("msg").toString();
String routingKey = param.get("key").toString();
rabbitTemplate.convertAndSend("BlogExchange", routingKey, msg);
return "OK";
}
}
package com.java.rabbitmq.consumer.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;
/**
* @author Woo_home
* @create 2020/5/28 21:08
*/
@Configuration
public class BlogConfig {
// 声明交换机
@Bean
public TopicExchange blogExchange() {
return new TopicExchange("BlogExchange");
}
// 声明队列名称
@Bean
public Queue blogJavaQueue() {
return new Queue("BlogQueue", true);
}
// 声明队列名称
@Bean
public Queue blogJavaNotQueue() {
return new Queue("BlogDotNetQueue", true);
}
// 声明队列名称
@Bean
public Queue blogAllQueue() {
return new Queue("BlogAllQueue", true);
}
// 绑定队列和交换机
@Bean
public Binding bindingToJavaQueue() {
return BindingBuilder.bind(blogJavaQueue())
.to(blogExchange())
.with("blog.java");
}
// 绑定队列和交换机
@Bean
public Binding bindingToDotNetQueue() {
return BindingBuilder.bind(blogJavaNotQueue())
.to(blogExchange())
.with("blog.doNet");
}
// 绑定队列和交换机
@Bean
public Binding bindingToAllQueue() {
return BindingBuilder.bind(blogAllQueue())
.to(blogExchange())
// 表示只要是 blog 开头的即可
.with("blog.#");
}
}
package com.java.rabbitmq.consumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author Woo_home
* @create 2020/5/28 21:25
*/
@Component
public class BlogService {
// 监听队列
@RabbitListener(queues = "BlogQueue")
public void receiverJava(String msg) {
System.out.println("收到的 Java 消息是:" + msg);
}
// 监听队列
@RabbitListener(queues = "BlogDotNetQueue")
public void receiverDotNet(String msg) {
System.out.println("收到的 DotNet 消息是:" + msg);
}
// 监听队列
@RabbitListener(queues = "BlogAllQueue")
public void receiverAll(String msg) {
System.out.println("收到的 All 消息是:" + msg);
}
}
访问 http://localhost:15672/#/exchanges ,可以发现,BlogExchange 已经添加进来
声明的队列
绑定的交换机和队列
访问 http://localhost:8081/topic?msg=SpringBoot整合RabbitMQ&key=blog.java
控制台输出(只要是以 .java 结尾或者 .# 都可以输出)
访问 .doNet 结尾的也是可以的
控制台输出:
package com.java.rabbitmq.producer.config;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Woo_home
* @create 2020/5/27 14:09
*/
@Configuration
public class FanoutConfig {
// 声明交换机
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange("FanoutExchange");
}
}
package com.java.rabbitmq.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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @author Woo_home
* @create 2020/5/27 14:30
*/
@RestController
public class AMQPController {
// 注入 RabbitTemplate 模板
@Autowired
public RabbitTemplate rabbitTemplate;
@GetMapping("/direct")
public String sendEmail(@RequestParam Map<String, Object> param) {
// 获取参数
String msg = param.get("msg").toString();
// 发送消息
rabbitTemplate.convertAndSend("EmailExchange", "EmailRouting", msg);
return "OK";
}
@GetMapping("/topic")
public String sendBlog(@RequestParam Map<String, Object> param) {
String msg = param.get("msg").toString();
String routingKey = param.get("key").toString();
rabbitTemplate.convertAndSend("BlogExchange", routingKey, msg);
return "OK";
}
@GetMapping("/fanout")
public String sendFanout(@RequestParam Map<String, Object> param) {
String msg = param.get("msg").toString();
rabbitTemplate.convertAndSend("FanoutExchange", null, msg);
return "OK";
}
}
package com.java.rabbitmq.consumer.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Woo_home
* @create 2020/5/27 14:09
*/
@Configuration
public class FanoutConfig {
// 声明交换机
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange("FanoutExchange");
}
// 声明队列
@Bean
public Queue fanoutQueue() {
return new Queue("FanoutQueue");
}
// 声明队列
@Bean
public Queue fanoutQueue2() {
return new Queue("FanoutQueue2");
}
// 绑定交换机和队列
@Bean
public Binding bindFanout() {
return BindingBuilder
.bind(fanoutQueue())
.to(fanoutExchange());
}
// 绑定交换机和队列
@Bean
public Binding bindFanout2() {
return BindingBuilder
.bind(fanoutQueue2())
.to(fanoutExchange());
}
}
这个类很简单,就打印接收的消息即可
package com.java.rabbitmq.consumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author Woo_home
* @create 2020/5/27 14:49
*/
@Component
public class FanoutService {
@RabbitListener(queues = "FanoutQueue")
public void receive(String msg) {
System.out.println("收到的消息 " + msg);
}
@RabbitListener(queues = "FanoutQueue2")
public void receive2(String msg) {
System.out.println("收到的消息 " + msg);
}
}
启动生产者和消费者服务
声明的队列
声明的交换机
交换机绑定的队列
在浏览器中输入以下地址返回 OK 即可
控制台输出
完整代码已上传至码云, 代码下载地址
相关 MQ 文章阅读
ActiveMQ 下载、安装
ActiveMQ —— Java 连接 ActiveMQ(点对点)
ActiveMQ —— Java 连接 ActiveMQ(发布订阅 Topic)
ActiveMQ —— Broker
ActiveMQ —— Spring 整合 ActiveMQ
SpringBoot 整合 ActiveMQ