该指南将引导你逐步使用 Spring Integration 管道适配器和 Google Cloud Pub/Sub 作为底层消息交换机制在程序的不同部分之间或不同程之间交换消息。
一个 Spring Boot Web 应用,它向自身发送消息并处理这些消息。
像大多数的 Spring 入门指南一样,你可以从头开始并完成每个步骤,也可以绕过你已经熟悉的基本设置步骤。如论哪种方式,你最终都有可以工作的代码。
git clone https://github.com/spring-guides/gs-messaging-gcp-pubsub.git
gs-messaging-gcp-pubsub/initial
目录;待一切就绪后,可以检查一下 gs-messaging-gcp-pubsub/complete
目录中的代码。
首先,我们设置一个基本的构建脚本。在使用 Spring 构建应用时可以使用任何喜欢的构建系统,但此处包含使用 Gradle 和 Maven 所需的代码。如果你都不熟悉,请参阅使用 Gradle 构建 Java 项目或使用 Maven 构建 Java 项目。
在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello
:
└── src
└── main
└── java
└── hello
以下是初始 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 插件提供了许多方便的功能:
public static void main()
方法并将其标记为可运行类;首先,我们搭建一个基本的构建脚本。使用 Spring 构建应用时,可以使用任何喜欢的构建系统,但是此处包含了使用 Maven 所需的弟阿玛。如果你不熟悉 Maven,请参阅使用 Maven 构建 Java 项目。
在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello
:
└── src
└── main
└── java
└── hello
以下是初始 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 插件提供了许多方便的功能:
public static void main()
方法并将其标记为可运行类;如果我们使用的是 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 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()
方法启动应用。
我们可以结合 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 管道适配器来交换消息!
以下指南也可能会有所帮助:
想看指南的其他内容?请访问该指南的所属专栏:《Spring 官方指南》