SpringBoot 2 使用 SpringIntegration 与 Google Cloud Pub/Sub 进行消息传输

开篇词

该指南将引导你逐步使用 Spring Integration 管道适配器Google Cloud Pub/Sub 作为底层消息交换机制在程序的不同部分之间或不同程之间交换消息。
 

你将创建的应用

一个 Spring Boot Web 应用,它向自身发送消息并处理这些消息。
 

你将需要的工具

  • 大概 15 分钟左右;
  • 你最喜欢的文本编辑器或集成开发环境(IDE)
  • JDK 1.8 或更高版本;
  • Gradle 4+Maven 3.2+
  • 你还可以将代码直接导入到 IDE 中:
    • Spring Too Suite (STS)
    • IntelliJ IDEA
  • 启用了结算和发布/订阅的 Google Cloud Platform 项目
  • Google Cloud SDK
     

如何完成这个指南

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

  • 要从头开始,移步至从 Spring Initializr 开始
  • 要跳过基础,执行以下操作:
    • 下载并解压缩该指南将用到的源代码,或借助 Git 来对其进行克隆操作:git clone https://github.com/spring-guides/gs-messaging-gcp-pubsub.git
    • 切换至 gs-messaging-gcp-pubsub/initial 目录;
    • 跳转至该指南的添加需要的依赖

待一切就绪后,可以检查一下 gs-messaging-gcp-pubsub/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-spring-cloud-gcp'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

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

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


<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.0modelVersion>

    <groupId>org.springframeworkgroupId>
    <artifactId>gs-spring-cloud-gcpartifactId>
    <version>0.1.0version>

    <properties>
        <java.version>1.8java.version>
        <spring-boot-release.version>2.2.1.RELEASEspring-boot-release.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot-release.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

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

project>

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

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

用 IDE 来构建

  • 阅读如何将该指南直接导入 Spring Tool Suite
  • 阅读如何在 IntelliJ IDEA 中使用该指南。
     

添加需要的依赖

如果我们使用的是 Maven,请将以下内容添加到 pom.xml 文件中:

<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-gcp-starter-pubsubartifactId>
    dependency>

    <dependency>
        <groupId>org.springframework.integrationgroupId>
        <artifactId>spring-integration-coreartifactId>
    dependency>
    ...
dependencies>

或者,如果我们使用的是 Gradle:

dependencies {
    ...
    compile("org.springframework.cloud:spring-cloud-gcp-starter-pubsub:1.1.3.RELEASE")
    compile("org.springframework.integration:spring-integration-core")
    ...
}

如果我们使用的是 Maven,也强烈建议我们使用 Spring Cloud GCD 物料清单(BOM)来控制依赖的版本:

<properties>
    ...
    <spring-cloud-gcp.version>1.1.3.RELEASEspring-cloud-gcp.version>
    ...
properties>

<dependencyManagement>
    <dependencies>
       ...
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-gcp-dependenciesartifactId>
            <version>${spring-cloud-gcp.version}version>
            <type>pomtype>
            <scope>importscope>
        dependency>
        ...
    dependencies>
dependencyManagement>

 

搭建 Google Pub/Sub 环境

我们需要一个主题和一个订阅,才能从 Google Cloud Pub/Sub 发送和接收消息。我们可以在 Google Cloud Console 中创建它们,也可以使用 PubSubAdmin 类以编程方式创建它们。

在该练习中,创建一个名为 “testTopic” 的主题,并创建一个名为 “testSubscription” 的订阅。
 

创建应用文件

我们需要一个类来包含管道适配器和消息传递配置。与 Spring Boot 应用一样,使用 @SpringBootApplication 表头创建 PubSubApplication 类。

src/main/java/hello/PubSubApplication.java

@SpringBootApplication
public class PubSubApplication {

  public static void main(String[] args) throws IOException {
    SpringApplication.run(PubSubApplication.class, args);
  }

}

此外,由于我们正在构建 Web 应用,因此请创建 WebApplicationController 类以在控制器和配置逻辑之间进行分离。

src/main/java/hello/WebAppController.java

@RestController
public class WebAppController {
}

我们仍然缺少两个 HTML 和属性文件。

src/main/resources/static/index.html


<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Spring Integration GCP sampletitle>
head>
<body>
<div name="formDiv">
  <form action="/publishMessage" method="post">
    Publish message: <input type="text" name="message" /> <input type="submit" value="Publish!"/>
  form>
div>
body>
html>

src/main/resources/application.properties

#spring.cloud.gcp.project-id=[YOUR_GCP_PROJECT_ID_HERE]
#spring.cloud.gcp.credentials.location=file:[LOCAL_FS_CREDENTIALS_PATH]

Spring Cloud GCP Core Boot 启动器可以自动配置这两个属性,并使它们成为可选属性。属性文件中的属性始终优先于 Spring Boot 配置。Spring Cloud GCP Core Boot 启动器与 Spring Cloud GCP Pub/Sub Boot 启动器捆绑在一起。

除了其他几种来源外,还可以通过 GOOGLE_CLOUD_PROJECT 环境变量自动配置 GCP 项目 ID。OAuth2 凭据是通过 GOOGLE_APPLICATION_CREDENTIALS 环境变量自动配置的。如果安装了 Google Cloud SDK,则可以在与应用或父应用相同的过程中运行 gcloud auth application-default login 命令,轻松配置该环境变量。
 

创建入站管道适配器

入站管道适配器侦听来自 Google Cloud Pub/Sub 订阅的消息,并将其发送到应用中的 Spring 管道。

实例化入站管道适配器需要 PubSubTemplate 实例和现有订阅的名称。PubSubTemplate 是 Spring 的抽象概念,用于订阅 Google Cloud Pub/Sub 主题。Spring Cloud GCP Pub/Sub 引导启动器提供了一个自动配置的 PubSubTemplate 实例,我们可以将其简单地注入为方法参数。

src/main/java/hello/PubSubApplication.java

  @Bean
  public PubSubInboundChannelAdapter messageChannelAdapter(
    @Qualifier("pubsubInputChannel") MessageChannel inputChannel,
    PubSubTemplate pubSubTemplate) {
  PubSubInboundChannelAdapter adapter =
    new PubSubInboundChannelAdapter(pubSubTemplate, "testSubscription");
  adapter.setOutputChannel(inputChannel);
  adapter.setAckMode(AckMode.MANUAL);

  return adapter;
  }

默认情况下,消息确认模式在适配器中设置为自动。如示例所示,该行为可能会被覆盖。

实例化管道适配器后,必须配置适配器将接收到的消息发送到输出管道。

src/main/java/hello/PubSubApplication.java

  @Bean
  public MessageChannel pubsubInputChannel() {
  return new DirectChannel();
  }

连接到入站管道的是服务激活器,用于处理传入消息。

src/main/java/hello/PubSubApplication.java

  @Bean
  @ServiceActivator(inputChannel = "pubsubInputChannel")
  public MessageHandler messageReceiver() {
  return message -> {
    LOGGER.info("Message arrived! Payload: " + new String((byte[]) message.getPayload()));
    BasicAcknowledgeablePubsubMessage originalMessage =
    message.getHeaders().get(GcpPubSubHeaders.ORIGINAL_MESSAGE, BasicAcknowledgeablePubsubMessage.class);
    originalMessage.ack();
  };
  }

ServiceActivator 输入管道名称(例如 " pubsubInputChannel")必须与输入管道方法名称匹配。每当新消息到达该通道时,返回的 MessageHandler 都会对其进行处理。

在该示例中,仅通过记录其正文并进行确认即可处理该消息。在手动确认中,使用 BasicAcknowledgeablePubsubMessage 对象确认消息,该对象附加在 Message 标头上,可以使用 GcpPubSubHeaders.ORIGINAL_MESSAGE 键提取。
 

创建出站管道适配器

出站管道适配器侦听来自 Spring 管道的新消息,并将其发布到 Google Cloud Pub/Sub 主题。

实例化出站管道适配器需要 PubSubTemplate 和现有主题的名称。PubSubTemplate 是 Spring 的抽象,用于将消息发布到 Google Cloud Pub/Sub 主题。Spring Cloud GCP Pub/Sub Boot 启动器提供了一个自动配置的 PubSubTemplate 实例。

src/main/java/hello/PubSubApplication.java

  @Bean
  @ServiceActivator(inputChannel = "pubsubOutputChannel")
  public MessageHandler messageSender(PubSubTemplate pubsubTemplate) {
  return new PubSubMessageHandler(pubsubTemplate, "testTopic");
  }

我们可以使用 MessageGateway 将消息写入频道,然后将其发布到 Google Cloud Pub/Sub。

src/main/java/hello/PubSubApplication.java

  @MessagingGateway(defaultRequestChannel = "pubsubOutputChannel")
  public interface PubsubOutboundGateway {

  void sendToPubsub(String text);
  }

通过该代码,Spring 自动生成一个对象,然后可以将该对象自动连接到应用的私有字段中。

src/main/java/hello/WebAppController.java

  @Autowired
  private PubsubOutboundGateway messagingGateway;

 

添加控制器逻辑

向我们的控制器添加逻辑,使我们可以写入 Spring 管道:

src/main/java/hello/WebAppController.java

package hello;

import hello.PubSubApplication.PubsubOutboundGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.RedirectView;

@RestController
public class WebAppController {

  // tag::autowireGateway[]
  @Autowired
  private PubsubOutboundGateway messagingGateway;
  // end::autowireGateway[]

  @PostMapping("/publishMessage")
  public RedirectView publishMessage(@RequestParam("message") String message) {
  messagingGateway.sendToPubsub(message);
  return new RedirectView("/");
  }
}

 

鉴权

我们的应用必须通过 GOOGLE_APPLICATION_CREDENTIALS 环境变量或 spring.cloud.gcp.credentials.location 属性进行身份验证。

如果我们安装了 Google Cloud SDK,则可以使用 gcloud auth application-default 命令以我们的用户账户登陆。

或者,我们可以从 Google Cloud Console 下载服务账户凭据文件,然后将 application.properties 文件中的 spring.cloud.gcp.credentials.location 属性指向该文件。

作为 Spring 资源spring.cloud.gcp.credentials.location 也可以从文件系统之外的其他位置获得,例如 URL、类路径等等。
 

使应用可执行

尽管可以将该服务打包为传统的 WAR 文件以部署到外部应用服务器,但是下面演示的更简单的方法创建了一个独立的应用。我们将所有内容打包在一个可执行的 JAR 文件中,该文件由 Java main() 方法驱动。另外 ,我们可以使用 Spring 的支持将 Tomcat sevlet 容器作为 HTTP 运行时嵌入,而不是部署到外部实例。

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

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

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

构建可执行 JAR

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

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

java -jar build/libs/gs-messaging-gcp-pubsub-0.1.0.jar

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:java -jar build/libs/messaging-gcp-pubsub-0.0.1-SNAPSHOT.jar

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

java -jar target/gs-messaging-gcp-pubsub-0.1.0.jar

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:java -jar target/messaging-gcp-pubsub-0.0.1-SNAPSHOT.jar

我们还可以将 JAR 应用转换成 WAR 应用

显示日志记录输出。该服务应在几秒内启动并运行。
 

测试应用

现在该应用正在运行,我们可以对其进行测试。打开 http://localhost:8080,在输入文本框中键入一条消息,然后按 “Publish!” 按钮并确认消息已正确记录在我们的处理终端窗口中。
 

概述

恭喜你!我们刚刚开发了一个 Spring 应用,该应用使用 Spring Integration GCP Pub/Sub 管道适配器来交换消息!
 

参见

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

  • xxxx(尽请期待~)

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

你可能感兴趣的:(Spring,入门指南)