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

1. Tổng quan

Spring Integration cung cấp cho bạn một cơ chế nhắn tin để trao đổi Messages thông qua MessageChannels. Nó 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 bằng cách sử dụng 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

2. Thiết lập và yêu cầu

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

  1. Đăng nhập vào Google Cloud Console rồi tạo một dự án mới hoặc sử dụng lại một dự án hiện có. Nếu chưa có tài khoản Gmail hoặc Google Workspace, bạn phải tạo một tài khoản.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Tên dự án là tên hiển thị của những người tham gia dự án này. Đây là một chuỗi ký tự mà các API của Google không sử dụng. Bạn luôn có thể cập nhật thông tin này.
  • Mã dự án là giá trị duy nhất trên tất cả các dự án trên Google Cloud và không thể thay đổi (bạn không thể thay đổi mã này sau khi đã đặt). Cloud Console sẽ tự động tạo một chuỗi duy nhất; thường thì bạn không cần quan tâm đến chuỗi này. Trong hầu hết các lớp học lập trình, bạn sẽ cần tham chiếu đến Mã dự án (thường được xác định là PROJECT_ID). Nếu không thích mã nhận dạng được tạo, bạn có thể tạo một mã nhận dạng ngẫu nhiên khác. Hoặc bạn có thể thử tên người dùng của riêng mình để xem tên đó có được chấp nhận hay không. Bạn không thể thay đổi tên này sau bước này và tên này sẽ tồn tại trong suốt thời gian của dự án.
  • Để bạn nắm được thông tin, có một giá trị thứ ba là Số dự án mà một số API sử dụng. Tìm hiểu thêm về cả 3 giá trị này trong tài liệu.
  1. 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/API trên Cloud. Việc thực hiện lớp học lập trình này sẽ không tốn nhiều chi phí, nếu có. Để tắt các tài nguyên nhằm tránh bị tính phí ngoài phạm vi hướng dẫn này, bạn có thể xoá các tài nguyên đã tạo hoặc xoá dự án. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí trị giá 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 Cloud.

Kích hoạt Cloud Shell

  1. Trong Cloud Console, hãy nhấp vào Kích hoạt Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

Nếu đây là lần đầu tiên bạn khởi động Cloud Shell, bạn sẽ thấy một màn hình trung gian mô tả về Cloud Shell. Nếu bạn thấy màn hình trung gian, hãy nhấp vào Tiếp tục.

9c92662c6a846a5c.png

Quá trình cung cấp và kết nối với Cloud Shell chỉ mất vài giây.

9f0e51b578fecce5.png

Máy ảo này được trang bị tất cả các công cụ phát triển cần thiết. Nền tảng này cung cấp một thư mục chính có dung lượng 5 GB và chạy trong 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 của mình trong lớp học lập trình này bằng trình duyệt.

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 mã dự án của bạn.

  1. 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
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Chạy lệnh sau trong Cloud Shell để xác nhận rằng lệnh gcloud biết về dự án của bạn:
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].

3. Cung cấp tài nguyên Pub/Sub

Chuyển đến trang chủ đề Google Cloud Pub/Sub.

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

4c938409dc7169a6.png

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

e2daeec91537f672.png

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 New Subscription (Đăng ký mới).

975efa26e5054936.png

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.

f7a91d9e1cb48009.png

4. Khởi động ứng dụng Spring Boot

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=3.0.5 \
  -d dependencies=web,integration,cloud-gcp-pubsub \
  -d type=maven-project \
  -d baseDir=spring-integration-sender | tar -xzvf -

$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=3.0.5 \
  -d dependencies=web,integration,cloud-gcp-pubsub \
  -d type=maven-project \
  -d baseDir=spring-integration-receiver | tar -xzvf -

5. Tạo một ứng dụng để gửi tin nhắn

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 một trình chỉnh sửa văn bản từ vim, emacs hoặc nano, hãy khai báo một 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 các thông báo đó lên một chủ đề Google Cloud Pub/Sub.

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

...
import com.google.cloud.spring.pubsub.core.PubSubTemplate;
import com.google.cloud.spring.pubsub.integration.outbound.PubSubMessageHandler;

import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.ServiceActivator;
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 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 cho chủ đề exampleTopic của Google Cloud Pub/Sub.

Khi có bộ chuyển đổi 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 cũng cần 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 {
  ...
}

Đảm bảo bạn đặt JAVA_HOME thành phiên bản phù hợp.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

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 có chứa một 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.

6. Tạo một ứng dụng để nhận tin nhắn

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.

9799bee5fea95aa6.png

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 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 com.google.cloud.spring.pubsub.core.PubSubTemplate;
import com.google.cloud.spring.pubsub.integration.inbound.PubSubInboundChannelAdapter;

import org.springframework.beans.factory.annotation.Qualifier;

@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 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 có tin nhắn mới đến pubsubInputChannel. 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ý.

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);
  }
}

Đảm bảo rằng JAVA_HOME được đặt thành phiên bản phù hợp.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

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

$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081"

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 đến ứ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!

7. Dọn dẹp

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

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

8. Tóm tắt

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 thông điệp với nhau mà không tương tác với API Google Cloud Pub/Sub.

9. Xin chúc mừng!

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 Ghi công theo Creative Commons 2.0 Chung.