Nhắn tin với tích hợp Spring và Google Cloud Pub/Sub

Spring Integration cung cấp cho bạn một cơ chế nhắn tin để trao đổi Messages thông qua MessageChannels. Nền tảng này sử dụng bộ chuyển đổi kênh để giao tiếp với các hệ thống bên ngoài.

Trong bài tập này, chúng ta sẽ tạo 2 ứng dụng giao tiếp bằng cách sử dụng các bộ chuyển đổi kênh Spring Integration do Spring Cloud GCP cung cấp. Các bộ chuyển đổi này giúp Spring Integration sử dụng Google Cloud Pub/Sub làm phần phụ trợ trao đổi thông báo.

Bạn sẽ tìm hiểu cách sử dụng Cloud Shell và lệnh gcloud Cloud SDK.

Hướng dẫn này sử dụng mã mẫu trong hướng dẫn Bắt đầu sử dụng Spring Boot.

Kiến thức bạn sẽ học được

  • Cách trao đổi thông báo giữa các ứng dụng bằng Google Cloud Pub/Sub thông qua Spring Integration và Spring Cloud GCP

Bạn cần có

  • Một dự án trên Google Cloud Platform
  • Một trình duyệt, chẳng hạn như Chrome hoặc Firefox
  • Làm quen với các trình chỉnh sửa văn bản tiêu chuẩn của Linux, chẳng hạn như Vim, EMAC hoặc Nano

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc Đọc và hoàn thành bài tập

Bạn đánh giá thế nào về trải nghiệm xây dựng ứng dụng web HTML/CSS?

Người mới bắt đầu Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud Platform?

Người mới bắt đầu Trung cấp Thành thạo

Thiết lập môi trường theo tốc độ của riêng bạn

Nếu chưa có Tài khoản Google (Gmail hoặc Google Apps), bạn phải tạo một tài khoản. Đăng nhập vào bảng điều khiển Google Cloud Platform (console.cloud.google.com) rồi tạo một dự án mới:

Ảnh chụp màn hình từ 2016-02-10 12:45:26.png

Hãy nhớ mã dự án, một tên duy nhất trong tất cả các dự án trên Google Cloud (tên ở trên đã được sử dụng và sẽ không hoạt động đối với bạn, xin lỗi!). Sau này trong lớp học lập trình này, chúng ta sẽ gọi nó là PROJECT_ID.

Tiếp theo, bạn cần bật tính năng thanh toán trong Cloud Console để sử dụng các tài nguyên của Google Cloud.

Việc thực hiện lớp học lập trình này sẽ không tốn của bạn quá vài đô la, nhưng có thể tốn nhiều hơn nếu bạn quyết định sử dụng nhiều tài nguyên hơn hoặc nếu bạn để các tài nguyên đó chạy (xem phần "dọn dẹp" ở cuối tài liệu này).

Người dùng mới của Google Cloud Platform đủ điều kiện dùng thử miễn phí 300 USD.

Google Cloud Shell

Mặc dù có thể vận hành Google Cloud từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, chúng ta sẽ sử dụng Google Cloud Shell, một môi trường dòng lệnh chạy trên đám mây.

Kích hoạt Google Cloud Shell

Trên Bảng điều khiển GCP, hãy nhấp vào biểu tượng Cloud Shell trên thanh công cụ ở trên cùng bên phải:

Sau đó, hãy nhấp vào "Start Cloud Shell" (Bắt đầu Cloud Shell):

Quá trình cung cấp và kết nối với môi trường chỉ mất vài phút:

Máy ảo này được trang bị tất cả các công cụ phát triển mà bạn cần. Nó cung cấp một thư mục chính có dung lượng 5 GB và chạy trên Google Cloud, giúp tăng cường đáng kể hiệu suất mạng và hoạt động xác thực. Bạn có thể thực hiện hầu hết, nếu không muốn nói là tất cả, công việc trong phòng thí nghiệm này chỉ bằng một trình duyệt hoặc Google Chromebook.

Sau khi kết nối với Cloud Shell, bạn sẽ thấy rằng mình đã được xác thực và dự án đã được đặt thành PROJECT_ID.

Chạy lệnh sau trong Cloud Shell để xác nhận rằng bạn đã được xác thực:

gcloud auth list

Đầu ra của lệnh

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Đầu ra của lệnh

[core]
project = <PROJECT_ID>

Nếu không, bạn có thể đặt nó bằng lệnh sau:

gcloud config set project <PROJECT_ID>

Đầu ra của lệnh

Updated property [core/project].

Chuyển đến trang chủ đề Google Cloud Pub/Sub rồi bật API.

Nhấp vào Tạo chủ đề.

Nhập exampleTopic làm tên của chủ đề, sau đó nhấp vào Tạo.

Sau khi tạo chủ đề, hãy vẫn ở trên trang Chủ đề. Tìm chủ đề bạn vừa tạo, nhấn vào biểu tượng ba dấu chấm dọc ở cuối dòng rồi nhấp vào Đăng ký mới.

Nhập exampleSubscription vào hộp văn bản tên gói thuê bao rồi nhấp vào Tạo.

Sau khi Cloud Shell khởi chạy, bạn có thể sử dụng dòng lệnh để tạo 2 ứng dụng Spring Boot mới bằng Spring Initializr:

$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=2.0.6.RELEASE \
  -d dependencies=web \
  -d baseDir=spring-integration-sender | tar -xzvf -
$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=2.0.6.RELEASE \
  -d baseDir=spring-integration-receiver | tar -xzvf -

Bây giờ, hãy tạo ứng dụng gửi tin nhắn. Chuyển đến thư mục của ứng dụng gửi.

$ cd spring-integration-sender

Chúng tôi muốn ứng dụng của mình ghi tin nhắn vào một kênh. Sau khi một thông báo nằm trong kênh, thông báo đó sẽ được bộ chuyển đổi kênh gửi đi chọn. Bộ chuyển đổi này sẽ chuyển đổi thông báo đó từ thông báo Spring chung thành thông báo Google Cloud Pub/Sub và đăng thông báo đó lên một chủ đề Google Cloud Pub/Sub.

Để ứng dụng của chúng ta ghi vào một kênh, chúng ta có thể sử dụng cổng nhắn tin Spring Integration. Sử dụng trình chỉnh sửa văn bản từ vim, emacs hoặc nano, khai báo giao diện PubsubOutboundGateway bên trong lớp DemoApplication.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.integration.annotation.MessagingGateway;

@SpringBootApplication
public class DemoApplication {

        ...

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

                void sendToPubsub(String text);
        }
}

Giờ đây, chúng ta đã có cơ chế gửi thông báo đến một kênh, nhưng những thông báo đó sẽ đi đâu sau khi vào kênh?

Chúng ta cần một bộ điều hợp kênh gửi đi để sử dụng các thông báo mới trong kênh và đăng chúng lên một chủ đề Google Cloud Pub/Sub.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.cloud.gcp.pubsub.integration.outbound.PubSubMessageHandler;
import org.springframework.messaging.MessageHandler;

@SpringBootApplication
public class DemoApplication {

        ...

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

Chú thích @ServiceActivator khiến chú thích MessageHandler này được áp dụng cho mọi tin nhắn mới trong inputChannel. Trong trường hợp này, chúng ta đang gọi bộ chuyển đổi kênh gửi đi PubSubMessageHandler để xuất bản thông báo đến chủ đề exampleTopic của Google Cloud Pub/Sub.

Khi đã có bộ điều hợp kênh, giờ đây, chúng ta có thể tự động kết nối một đối tượng PubsubOutboundGateway và dùng đối tượng đó để viết thông báo vào một kênh.

src/main/java/com/example/demo/DemoApplication.java

...
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.servlet.view.RedirectView;

@SpringBootApplication
public class DemoApplication {

...

        @Autowired
        private PubsubOutboundGateway messagingGateway;

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

Nhờ chú thích @PostMapping, giờ đây chúng ta có một điểm cuối đang lắng nghe các yêu cầu HTTP POST, nhưng không phải là không thêm chú thích @RestController vào lớp DemoApplication để đánh dấu lớp này là một bộ điều khiển REST.

src/main/java/com/example/demo/DemoApplication.java

import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {
  ...
}

Để ứng dụng chạy, chúng ta chỉ cần thêm các phần phụ thuộc bắt buộc.

pom.xml

<project>
  ...
  <!-- Add Spring Cloud GCP Dependency BOM -->
  <dependencyManagement>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-gcp-dependencies</artifactId>
                        <version>1.0.0.RELEASE</version>
                        <type>pom</type>
                        <scope>import</scope>
                </dependency>
        </dependencies>
  </dependencyManagement>

  <dependencies>
        ...
        <!-- Add Pub/Sub Starter -->
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
        </dependency>

        <!-- Add Spring Integration -->
        <dependency>
                <groupId>org.springframework.integration</groupId>
                <artifactId>spring-integration-core</artifactId>
        </dependency>

  </dependencies>

</project>

Chạy ứng dụng người gửi.

# Set the Project ID in environmental variable
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list \
  --format 'value(core.project)'`
$ ./mvnw spring-boot:run

Ứng dụng đang lắng nghe các yêu cầu POST chứa thông báo trên cổng 8080 và điểm cuối /postMessage, nhưng chúng ta sẽ đề cập đến vấn đề này sau.

Chúng ta vừa tạo một ứng dụng gửi thông báo qua Google Cloud Pub/Sub. Bây giờ, chúng ta sẽ tạo một ứng dụng khác để nhận và xử lý những thông báo đó.

Nhấp vào + để mở một phiên Cloud Shell mới.

Sau đó, trong phiên Cloud Shell mới, hãy thay đổi thư mục thành thư mục của ứng dụng nhận:

$ cd spring-integration-receiver

Trong ứng dụng trước, khai báo cổng nhắn tin đã tạo kênh gửi đi cho chúng ta. Vì không sử dụng cổng nhắn tin để nhận tin nhắn, nên chúng ta cần khai báo MessageChannel của riêng mình, nơi tin nhắn đến sẽ xuất hiện.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.context.annotation.Bean;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.messaging.MessageChannel;

@SpringBootApplication
public class DemoApplication {

        ...

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

Chúng ta sẽ cần bộ chuyển đổi kênh đầu vào để nhận thông báo từ Google Cloud Pub/Sub và chuyển tiếp thông báo đó đến pubsubInputChannel.

src/main/java/com/example/demo/DemoApplication.java

...
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.cloud.gcp.pubsub.integration.inbound.PubSubInboundChannelAdapter;

@SpringBootApplication
public class DemoApplication {
        ...

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

                return adapter;
        }
}

Bộ chuyển đổi này tự liên kết với pubsubInputChannel và lắng nghe các thông báo mới từ gói thuê bao exampleSubscription Google Cloud Pub/Sub.

Chúng tôi có một kênh để đăng các tin nhắn đến, nhưng chúng tôi nên làm gì với những tin nhắn đó?

Hãy xử lý các thông báo này bằng một @ServiceActivator được kích hoạt khi tin nhắn mới đến pubsubInputChannel.

src/main/java/com/example/demo/DemoApplication.java

...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.annotation.ServiceActivator;

@SpringBootApplication
public class DemoApplication {

        ...

        private static final Log LOGGER = LogFactory.getLog(DemoApplication.class);

        @ServiceActivator(inputChannel = "pubsubInputChannel")
        public void messageReceiver(String payload) {
                LOGGER.info("Message arrived! Payload: " + payload);
        }
}

Trong trường hợp này, chúng ta chỉ cần ghi tải trọng thông báo vào nhật ký.

Chúng ta cần thêm các phần phụ thuộc cần thiết.

pom.xml

<project>
  ...
  <!-- Add Spring Cloud GCP Dependency BOM -->
  <dependencyManagement>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-gcp-dependencies</artifactId>
                        <version>1.0.0.RELEASE</version>
                        <type>pom</type>
                        <scope>import</scope>
                </dependency>
        </dependencies>
  </dependencyManagement>

  <dependencies>
        ...
        <!-- Add Pub/Sub Starter -->
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
        </dependency>

        <!-- Add Spring Integration -->
        <dependency>
                <groupId>org.springframework.integration</groupId>
                <artifactId>spring-integration-core</artifactId>
        </dependency>

  </dependencies>

</project>

Chạy ứng dụng nhận.

$ ./mvnw spring-boot:run

Giờ đây, mọi thông báo bạn gửi đến ứng dụng người gửi sẽ được ghi lại trên ứng dụng người nhận. Để kiểm tra, hãy mở một phiên Cloud Shell mới và đưa ra yêu cầu HTTP POST cho ứng dụng người gửi.

$ curl --data "message=Hello world!" localhost:8080/postMessage

Sau đó, hãy xác minh rằng ứng dụng nhận đã ghi lại thông báo mà bạn gửi!

INFO: Message arrived! Payload: Hello world!

Xoá gói thuê bao và chủ đề đã tạo trong bài tập này.

$ gcloud beta pubsub subscriptions delete exampleSubscription
$ gcloud beta pubsub topics delete exampleTopic

Bạn thiết lập 2 ứng dụng Spring Boot sử dụng Spring Integration Channel Adapters cho Google Cloud Pub/Sub. Chúng trao đổi tin nhắn với nhau mà không tương tác với API Google Cloud Pub/Sub.

Bạn đã tìm hiểu cách sử dụng Spring Integration Channel Adapters cho Google Cloud Pub/Sub!

Tìm hiểu thêm

Giấy phép

Tác phẩm này được cấp phép theo Giấy phép chung Ghi nhận tác giả theo Creative Commons 2.0.