SpringBoot 2 JMS 消息传输

开篇词

该指南将引导你完成使用 JMS 代理发布和订阅消息。
 

你将创建的应用

我们将构建一个应用,使用 Spring 的 JmsTemplate 发布单个消息并使用标注了 @JmsListener 注解的托管 Bean 方法对其进行订阅。
 

你将需要的工具

如何完成这个指南

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

  • 要从头开始,移步至用 Gradle 来构建
  • 要跳过基础,执行以下操作:
    • 下载并解压缩该指南将用到的源代码,或借助 Git 来对其进行克隆操作:git clone https://github.com/spring-guides/gs-messaging-jms.git
    • 切换至 gs-messaging-jms/initial 目录;
    • 跳转至该指南的创建消息接收器

待一切就绪后,可以检查一下 gs-messaging-jms/complete 目录中的代码。
 

用 Gradle 来构建

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

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

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

创建 Gradle 构建文件

以下是初始 Gradle 构建文件。
build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.1.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-jms'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-activemq")
    compile("org.apache.activemq:activemq-broker")
    compile("com.fasterxml.jackson.core:jackson-databind")
}

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

  • 它收集类路径上的所有 jar,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法并将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用于设置版本号以及匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。
     

用 Maven 来构建

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

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

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

创建 Maven 构建文件

以下是初始 Maven 构建文件。
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-jms</artifactId>
    <version>0.1.0</version>

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

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</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,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法并将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用于设置版本号以及匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。
     

用 IDE 来构建

创建消息接收器

Spring 提供了将消息发布到任何 POJO 的方法。

在该指南中,我们将研究如何通过 JMS 消息代理发送消息。首先,让我们创建一个非常简单的 POJO,其中体现了电子邮件的详细信息。请注意,我们不会发送电子邮件。我们只是将详细信息从一个地方发送到另一个地方。

src/main/java/hello/Email.java

package hello;

public class Email {

  private String to;
  private String body;

  public Email() {
  }

  public Email(String to, String body) {
    this.to = to;
    this.body = body;
  }

  public String getTo() {
    return to;
  }

  public void setTo(String to) {
    this.to = to;
  }

  public String getBody() {
    return body;
  }

  public void setBody(String body) {
    this.body = body;
  }

  @Override
  public String toString() {
    return String.format("Email{to=%s, body=%s}", getTo(), getBody());
  }

}

这个 POJO 非常简单,包含 to 和 body 两个字段以及假定的 getter 和 setter。

在这里,我们可以定义消息接收器:

src/main/java/hello/Receiver.java

package hello;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class Receiver {

  @JmsListener(destination = "mailbox", containerFactory = "myFactory")
  public void receiveMessage(Email email) {
    System.out.println("Received <" + email + ">");
  }

}

Receiver 也称为消息驱动的 POJO。如我们在上面的代码中看到的,不需要实现任何特定的接口,也不需要使该方法具有任何特定的名称。此外,该方法可以具有非常灵活的签名。特别注意,该类并未导入 JMS API。

JmsListener 注解定义该方法应监听的 Destination 名称,以及对 JmsListenerContainerFactory 的引用,以用于创建基础消息监听器容器。严格来说,除非我们需要自定义容器的构建方式,否则不需要最后一个属性,因为 Spring Boot 会在必要时注册默认工厂。

参考文档对此进行了更详细的介绍。
 

结合 Spring 来收发 JMS 消息

接下来,我们来对接一下发送方与接收方。

src/main/java/hello/Application.java

package hello;

import javax.jms.ConnectionFactory;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;

@SpringBootApplication
@EnableJms
public class Application {

  @Bean
  public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                          DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    // This provides all boot's default to this factory, including the message converter
    configurer.configure(factory, connectionFactory);
    // You could still override some of Boot's default if necessary.
    return factory;
  }

  @Bean // Serialize message content to json using TextMessage
  public MessageConverter jacksonJmsMessageConverter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    converter.setTargetType(MessageType.TEXT);
    converter.setTypeIdPropertyName("_type");
    return converter;
  }

  public static void main(String[] args) {
    // Launch the application
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

    JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);

    // Send a message with a POJO - the template reuse the message converter
    System.out.println("Sending an email message.");
    jmsTemplate.convertAndSend("mailbox", new Email("info@example.com", "Hello"));
  }

}

@SpringBootApplication 是一个便利的注解,它添加了以下所有内容:

  • @Configuration:将类标记为应用上下文 Bean 定义的源;
  • @EnableAutoConfiguration:告诉 Spring Boot 根据类路径配置、其他 bean 以及各种属性的配置来添加 bean。
  • @ComponentScan:告知 Spring 在 hello 包中寻找他组件、配置以及服务。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法启动应用。

@EnableJms 触发发现标注了 @JmsListener 注解的方法,在幕后创建消息监听器容器。

为清晰起见,我们还定义了一个 myFactory bean,该 bean 在接收方的 JmsListener 注解中被引用。因为我们使用的是 Spring Boot 提供的 DefaultJmsListenerContainerFactoryConfigurer 基础结构,所以该 JmsMessageListenerContainer 与启动时默认创建的那个一致。

默认的 MessageConverter 只能转换基本类型(例如 StringMapSerializable),而我们的 Email 不是有意进行 Serializable 的。我们想使用 Jackson 并将内容以文本格式(即作为 TextMessage)序列化为 json。Spring Boot 将监测到 MessageConverter 的存在,并将其与默认 JmsTemplate 以及 DefaultJmsListenerContainerFactoryConfigurer 创建的任何 JmsListenerContainerFactory 关联。

JmsTemplate 使发送消息到 Jms 目的地变得非常简单。在 main 运行器方法中,启动之后,我们可以使用 jmsTemplate 发送 Email POJO。因为我们的自定义 MessageConverter 已自动与其关联,所以将仅在 TextMessage 中生成一个 json 文档。

所定义的两个我们没有看到的 bean 是 JmsTemplateConnectionFactory。这些是由 Spring Boot 自动创建的。在这种情况下,ActiveMQ broker 以嵌入方式运行。

默认情况下,Spring Boot 通过将 pubSubDomain 设置为 false 来创建一个 JmsTemplate,该 JmsTemplate 配置为传输到队列JmsMessageListenerContainer 的配置也相同。要进行覆盖,请通过 Boot 的属性设置(在 application.properties 内部或通过环境变量)设置 spring.jms.isPubSubDomain = true。然后确保接收容器的设置相同。

Spring 的 JmsTemplate 可以直接通过其 receive 方法接收消息,但这只能同步工作,这意味着它将阻塞。因此,我们建议将监听器容器(例如 DefaultMessageListenerContainer)与基于缓存的连接工厂一起使用,以便可以异步消费消息并以最大化连接效率。
 

构建可执行 JAR

我们可以结合 Gradle 或 Maven 来从命令行运行该应用。我们还可以构建一个包含所有必须依赖项、类以及资源的可执行 JAR 文件,然后运行该文件。在整个开发生命周期中,跨环境等等情况下,构建可执行 JAR 可以轻松地将服务作为应用进行发布、版本化以及部署。

如果使用 Gradle,则可以借助 ./gradlew bootRun 来运行应用。或通过借助 ./gradlew build 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

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

如果使用 Maven,则可以借助 ./mvnw spring-boot:run 来运行该用。或可以借助 ./mvnw clean package 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar target/gs-messaging-jms-0.1.0.jar

我们还可以构建一个经典的 WAR 文件

当它运行时,在被淹没在日志输出中,我们应该看到以下消息:

Sending an email message.
Received <Email{to=info@example.com, body=Hello}>

 

概述

恭喜你!我们刚刚开发了基于 JMS 消息的发布器和接收器。
 

参见

想看指南的其他内容?请访问该指南的所属专栏:《Spring 官方指南

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值