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,添加如下内容:


org.springframework.boot
spring-boot-starter-parent

1.5.20.RELEASE


<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>




org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import


在spring-boot-rabbitmq主工程中创建一个RabbitMQ配置的Maven module:rabbitmq-config
添加如下依赖:


org.springframework.boot
spring-boot-starter-amqp

创建一个配置类: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文件中添加如下依赖:


org.springframework.boot
spring-boot-starter-web


com.alyshen
rabbitmq-config
${project.version}


org.springframework.boot
spring-boot-starter-amqp

在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文件中添加如下依赖:


org.springframework.boot
spring-boot-starter-web


com.alyshen
rabbitmq-config
${project.version}


org.springframework.boot
spring-boot-starter-amqp

在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依赖


com.alyshen
rabbitmq-model
${project.version}

在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交换机上的队列都接收到了消息

posted @ 2019-07-02 00:47  Douoiv  阅读(234)  评论(0)    收藏  举报