本指南将引导您完成设置发布和订阅消息的RabbitMQ AMQP服务器的过程。

你会建立什么

您将使用Spring AMQP构建一个发布消息的应用程序RabbitTemplate并使用订阅POJO上的消息MessageListenerAdapter

你需要什么

如何完成本指南

像大多数Spring 入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都可以使用工作代码。

从头开始 ,请继续使用Gradle构建

跳过基础知识 ,请执行以下操作:

完成后 ,您可以根据中的代码检查结果gs-messaging-rabbitmq/complete

用Gradle构建

用Gradle构建

首先,您设置一个基本的构建脚本。在使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含使用GradleMaven所需的代码。如果您都不熟悉,请参阅使用Gradle 构建Java项目使用Maven构建Java项目

创建目录结构

在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello在* nix系统上:

└── src
    └── main
        └── java
            └── hello

创建一个Gradle构建文件

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-messaging-rabbitmq'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-amqp")
    testCompile("junit:junit")
}

Spring Boot gradle插件提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。

  • 它搜索public static void main()标记为可运行类的方法。

  • 它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。

用Maven构建

用Maven构建

首先,您设置一个基本的构建脚本。使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含了使用Maven所需的代码。如果您不熟悉Maven,请参阅使用Maven 构建Java项目

创建目录结构

在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello在* nix系统上:

└── src
    └── main
        └── java
            └── hello

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>

    <groupId>org.springframework</groupId>
    <artifactId>gs-messaging-rabbitmq</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Boot Maven插件提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。

  • 它搜索public static void main()标记为可运行类的方法。

  • 它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。

使用您的IDE进行构建

使用您的IDE进行构建

设置RabbitMQ经纪人

在构建消息传递应用程序之前,您需要设置将处理接收和发送消息的服务器。

RabbitMQ是AMQP服务器。该服务器可从https://www.rabbitmq.com/download.html免费获得。您可以手动下载它,或者如果您使用带有自制软件的Mac:

brew install rabbitmq

打开服务器包装,并使用默认设置启动它。

rabbitmq-server

您应该会看到以下内容:

            RabbitMQ 3.1.3. Copyright (C) 2007-2013 VMware, Inc.
##  ##      Licensed under the MPL.  See https://www.rabbitmq.com/
##  ##
##########  Logs: /usr/local/var/log/rabbitmq/[email protected]
######  ##        /usr/local/var/log/rabbitmq/[email protected]
##########
            Starting broker... completed with 6 plugins.

如果您在本地运行docker,也可以使用Docker Compose快速启动RabbitMQ服务器。有一个docker-compose.yml在Github中“完整”项目的根目录中。这很简单:

docker-compose.yml

rabbitmq:
  image: rabbitmq:management
  ports:
    - "5672:5672"
    - "15672:15672"

使用此文件在当前目录中,您可以运行docker-compose up使RabbitMQ在容器中运行。

创建RabbitMQ消息接收器

对于任何基于消息传递的应用程序,您需要创建一个接收器,该接收器将响应已发布的消息。

src/main/java/hello/Receiver.java

package hello;

import java.util.concurrent.CountDownLatch;
import org.springframework.stereotype.Component;

@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,它定义了一种接收消息的方法。注册它以接收消息时,可以随意命名。

为方便起见,此POJO还具有一个CountDownLatch 。这使其可以发出已接收到该消息的信号。这是您不太可能在生产应用程序中实现的东西。

注册侦听器并发送消息

Spring AMQP RabbitTemplate提供使用RabbitMQ发送和接收消息所需的一切。具体来说,您需要配置:

  • 消息侦听器容器

  • 声明队列,交换以及它们之间的绑定

  • 发送一些消息以测试侦听器的组件

Spring Boot自动创建一个连接工厂和一个RabbitTemplate,从而减少了您必须编写的代码量。

您将使用RabbitTemplate发送消息,您将注册一个Receiver与消息侦听器容器一起接收消息。连接工厂驱动两者,从而允许它们连接到RabbitMQ服务器。

src/main/java/hello/Application.java

package hello;

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

    static final String topicExchangeName = "spring-boot-exchange";

    static final String queueName = "spring-boot";

    @Bean
    Queue queue() {
        return new Queue(queueName, false);
    }

    @Bean
    TopicExchange exchange() {
        return new TopicExchange(topicExchangeName);
    }

    @Bean
    Binding binding(Queue queue, TopicExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#");
    }

    @Bean
    SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
            MessageListenerAdapter listenerAdapter) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames(queueName);
        container.setMessageListener(listenerAdapter);
        return container;
    }

    @Bean
    MessageListenerAdapter listenerAdapter(Receiver receiver) {
        return new MessageListenerAdapter(receiver, "receiveMessage");
    }

    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(Application.class, args).close();
    }

}

@SpringBootApplication是一个方便注释,它添加了以下所有内容:

  • @Configuration :将类标记为应用程序上下文的Bean定义的源。

  • @EnableAutoConfiguration :告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,此注释将应用程序标记为Web应用程序并激活关键行为,例如设置DispatcherServlet

  • @ComponentScan :告诉Spring在其中寻找其他组件,配置和服务hello包,让它找到控制器。

main()方法使用Spring Boot的SpringApplication.run()启动应用程序的方法。您是否注意到没有一行XML?没有web.xml文件。该Web应用程序是100%纯Java,因此您无需处理任何管道或基础结构。

在中定义的bean listenerAdapter()方法已在中定义的容器中注册为消息侦听器container() 。它将在“ spring-boot”队列上侦听消息。因为Receiver类是一个POJO,需要包装在MessageListenerAdapter ,在其中指定要调用的位置receiveMessage

JMS队列和AMQP队列具有不同的语义。例如,JMS仅将排队的消息发送给一个使用者。尽管AMQP队列执行相同的操作,但AMQP生产者不会将消息直接发送到队列。而是将消息发送到交换机,该交换机可以转到单个队列,也可以扇出到多个队列,以模拟JMS主题的概念。有关更多信息,请参阅了解AMQP

消息侦听器容器和接收者Bean就是您侦听消息所需的全部。要发送消息,您还需要Rabbit模板。

queue()方法创建一个AMQP队列。的exchange()方法创建主题交流。的binding()方法将这两者绑定在一起,定义当RabbitTemplate发布到交易所时发生的行为。

Spring AMQP要求QueueTopicExchangeBinding被声明为顶级Spring Bean,以便正确设置。

在这种情况下,我们使用主题交换,并且队列与路由键绑定foo.bar.#这意味着任何以路由键开头的消息都以foo.bar.将被路由到队列。

发送测试信息

测试消息由CommandLineRunner ,它还会等待接收器中的闩锁并关闭应用程序上下文:

src/main/java/hello/Runner.java

package hello;

import java.util.concurrent.TimeUnit;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class Runner implements CommandLineRunner {

    private final RabbitTemplate rabbitTemplate;
    private final Receiver receiver;

    public Runner(Receiver receiver, RabbitTemplate rabbitTemplate) {
        this.receiver = receiver;
        this.rabbitTemplate = rabbitTemplate;
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Sending message...");
        rabbitTemplate.convertAndSend(Application.topicExchangeName, "foo.bar.baz", "Hello from RabbitMQ!");
        receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
    }

}

请注意,模板使用以下路由键将消息路由到交换机foo.bar.baz匹配绑定。

可以在测试中模拟流道,以便可以单独测试接收器。

运行应用程序

main()方法通过创建Spring应用程序上下文来启动该过程。这将启动消息侦听器容器,该容器将开始侦听消息。有一个Runner然后自动执行的bean:它检索RabbitTemplate从应用程序上下文中发送一个“来自RabbitMQ的问候!“ spring-boot”队列中的消息。最后,它关闭Spring应用程序上下文并结束应用程序。

构建可执行的JAR

您可以使用Gradle或Maven从命令行运行该应用程序。您还可以构建一个包含所有必需的依赖项,类和资源的可执行JAR文件,然后运行该文件。构建可执行的jar使得在整个开发生命周期中,跨不同环境等等的情况下,可以轻松地将服务作为应用程序进行发布,版本化和部署。

如果您使用Gradle,则可以使用./gradlew bootRun 。或者,您可以通过使用以下命令构建JAR文件: ./gradlew build然后运行JAR文件,如下所示:

java -jar build/libs/gs-messaging-rabbitmq-0.1.0.jar

如果使用Maven,则可以通过使用以下命令运行应用程序./mvnw spring-boot:run 。或者,您可以使用以下命令构建JAR文件: ./mvnw clean package然后运行JAR文件,如下所示:

java -jar target/gs-messaging-rabbitmq-0.1.0.jar
此处描述的步骤将创建可运行的JAR。您还可以构建经典的WAR文件

您应该看到以下输出:

Sending message...
Received <Hello from RabbitMQ!>

摘要

恭喜你!您刚刚使用Spring和RabbitMQ开发了一个简单的发布和订阅应用程序。 使用Spring和RabbitMQ可以做的比这里介绍的要多,但这应该是一个很好的开始。

也可以看看

以下指南也可能会有所帮助:

是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则

所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创作共用许可证发布