本章带你设置一个RabbitMQ AMQP服务器来发布和订阅消息,创建一个Spring Boot应用和RabbitMQ服务器进行交互。
本文目标
用Spring Boot构建一个应用,使用Spring AMQP的RabbitTemplate发布消息,使用MessageListenerAdapter订阅消息。
你需要
- 15分钟左右
- IntelliJ IDEA
- JDK 1.8+
- Maven 3.2+
- RabbitMQ服务器
设置一个RabbitMQ服务器
在创建一个消息应用之前,我们需要配置一个负责接收信息和发送信息的服务器。
Redis是一个AMQP服务器。
安装方法可以参照这篇文章RabbitMQ安装教程(Windows/Linux都有)。
用Spring Initializr生成项目代码
对于所有的Spring应用,你都可以使用Spring Initializr生成基本的项目代码。Initializr提供了一个快速的方式去引入所有你需要的依赖,并且为你做了很多设置。当前例子需要Spring for RabbitMQ依赖。
具体设置如下图:
如上图所示,我们选择了Maven作为编译工具。你也可以选择Gradle来进行编译。然后我们分别把Group和Artifact设置为“com.hansy”和“messaging-rabbitmq”。
生成的pom.xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hansy</groupId>
<artifactId>messaging-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>messaging-rabbitmq</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建一个RabbitMQ消息接收器
在任何的基于消息的应用中,都需要一个消息接收器,拥有一个可以响应消息的方法。代码如下:
package com.hansy.messagingrabbitmq;
import org.springframework.stereotype.Component;
import java.util.concurrent.CountDownLatch;
@Component
public class Receiver {
private CountDownLatch latch = new CountDownLatch(1);
public void receiveMessage(String message) {
System.out.println("Received <" + message + ">");
latch.countDown();
}
public CountDownLatch getLatch() {
return latch;
}
}
Receiver是一个定义了接收消息的方法的POJO类。当你注册了一个Receiver作为消息监听器的话,消息处理方法的命名可以随意。
为了方便,这个POJO类还有一个CountDownLatch对象。用来标志接收到了信息。这么做这是只是为了测试,实际生产环境不太可能这么使用。
注册监听器和发送消息
Spring AMQP的RabbitTemplate提供了使用RabbitMQ来发送和接收消息的所有功能。
我们需要配置如下元素:
- 一个消息监听器的容器
- 定义Queue,Exchange和用于他们之间的Binding
- 配置一个组件去发送一些消息去测试监听器
Spring Boot会自动创建一个连接工厂和一个RabbitTemplate,减少了额外的代码。
我们使用RabbitTemplate发送消息,注册一个Receiver到消息监听器的容器里面来接收消息。连接工厂驱动他们连接到RabbitMQ服务器。代码如下:
package com.hansy.messagingrabbitmq;
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.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class MessagingRabbitmqApplication {
public static final String TOPIC_EXCHANGE_NAME = "spring-boot-exchange";
public static final String QUEUE_NAME = "spring-boot";
@Bean
Queue queue() {
return new Queue(QUEUE_NAME, false);
}
@Bean
TopicExchange exchange() {
return new TopicExchange(TOPIC_EXCHANGE_NAME);
}
@Bean
Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#");
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
@Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(QUEUE_NAME);
container.setMessageListener(listenerAdapter);
return container;
}
public static void main(String[] args) {
SpringApplication.run(MessagingRabbitmqApplication.class, args).close();
}
}
receiver()方法返回一个简单的Receiver对象,这个Receiver对象会被包装到listenerAdapter()方法返回的MessageListenerAdapter里面。再通过addMessageListener()方法添加到RedisMessageListenerContainer里面,对“spring-boot”队列里面的消息进行监听。当消息到达时,会调用Receiver对象的receiveMessage()方法。
JMS队列和AMQP队列的处理方式并不相同。例如,JMS发送排队的消息给单个消费者。但是,如果是AMQP队列的话,AMQP生产者不会直接把消息发到队列。相应的,消息会被发送给Exchange,然后可能进入单个队列,也可能划到多个队列,类似于JMS主题。
监听消息需要消息监听容器和接收器等一些类。而发送消息,则需要RabbitTemplate。
queue()方法创建了AMQP队列。exchange()方法创建了TopicExchange。binding()方法把两者绑定到一起。
为了能被正确地配置,Spring AMQP需要Queue、TopicExchange和Binding必须定义为顶级的Spring Bean。
本例中,TopicExchange和队列用一个路由关键字“foo.bar.#”绑定到了一起。消息的路由关键字如果以“foo.bar.”开头,都会被发送到我们指定的队列。
发送测试消息
首先发送测试消息,然后receiver中的锁存器进行等待,最后关闭程序。
代码如下:
package com.hansy.messagingrabbitmq;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class Runner implements CommandLineRunner {
private final RabbitTemplate template;
private final Receiver receiver;
public Runner(Receiver receiver, RabbitTemplate template) {
this.receiver = receiver;
this.template = template;
}
@Override
public void run(String... args) throws Exception {
System.out.println("Sending message...");
template.convertAndSend(MessagingRabbitmqApplication.TOPIC_EXCHANGE_NAME, "foo.bar.baz",
"Hello from RabbitMQ!");
receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
}
}
RabbitTemplate发送消息时,路由键为“foo.bar.baz”,匹配了Binding中设置的规则。
运行程序
main()方法首先创建一个SpringApplication上下文。然后Application上下文启动一个消息监听容器,而消息监听容器开始监听消息。然后定义了一个可以自动运行Runner类。 接着从上下文中取出一个RabbitTemplate对象,然后在“spring-boot”队列上发送一条消息“Hello from RabbitMQ!”。最后,关闭SpringApplication上下文,程序结束。
运行程序,结果如下:
Sending message...
Received <Hello from RabbitMQ!>
小结
你已经用Spring Boot开发了一个利用RabbitMQ完成发布与订阅的程序。