การรับส่งข้อความด้วยการผสานรวม Spring และ Google Cloud Pub/Sub

1. ภาพรวม

Spring Integration มีกลไกการรับส่งข้อความให้คุณแลกเปลี่ยน Messages ผ่าน MessageChannels โดยจะใช้ Channel Adapter เพื่อสื่อสารกับระบบภายนอก

ในแบบฝึกหัดนี้ เราจะสร้างแอป 2 แอปที่สื่อสารกันโดยใช้ Channel Adapter ของ Spring Integration ที่ Spring Cloud GCP จัดเตรียมไว้ให้ ซึ่งอะแดปเตอร์เหล่านี้จะทำให้ Spring Integration ใช้ Google Cloud Pub/Sub เป็นแบ็กเอนด์การแลกเปลี่ยนข้อความ

คุณจะได้ดูวิธีใช้ Cloud Shell และคำสั่ง gcloud ของ Cloud SDK

บทแนะนำนี้ใช้โค้ดตัวอย่างจากคู่มือการเริ่มต้นใช้งาน Spring Boot

สิ่งที่คุณจะได้เรียนรู้

  • วิธีแลกเปลี่ยนข้อความระหว่างแอปด้วย Google Cloud Pub/Sub โดยใช้ Spring Integration และ Spring Cloud GCP

สิ่งที่คุณต้องมี

  • โปรเจ็กต์ Google Cloud Platform
  • เบราว์เซอร์ เช่น Chrome หรือ Firefox
  • คุ้นเคยกับโปรแกรมแก้ไขข้อความมาตรฐานของ Linux เช่น Vim, EMAC หรือ Nano

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านอย่างเดียว อ่านและทำแบบฝึกหัด

คุณจะให้คะแนนประสบการณ์ในการสร้างเว็บแอป HTML/CSS เท่าใด

ผู้ฝึกหัด ขั้นกลาง ผู้ชำนาญ

คุณจะให้คะแนนประสบการณ์การใช้บริการ Google Cloud Platform เท่าใด

ผู้ฝึกหัด ขั้นกลาง ผู้ชำนาญ

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมแบบเรียนรู้ด้วยตนเอง

  1. ลงชื่อเข้าใช้ Google Cloud Console แล้วสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • ชื่อโปรเจ็กต์คือชื่อที่แสดงสำหรับผู้เข้าร่วมโปรเจ็กต์นี้ ซึ่งเป็นสตริงอักขระที่ Google APIs ไม่ได้ใช้ คุณอัปเดตได้ทุกเมื่อ
  • รหัสโปรเจ็กต์จะไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมดและเปลี่ยนแปลงไม่ได้ (เปลี่ยนไม่ได้หลังจากตั้งค่าแล้ว) Cloud Console จะสร้างสตริงที่ไม่ซ้ำกันโดยอัตโนมัติ ซึ่งโดยปกติแล้วคุณไม่จำเป็นต้องสนใจว่าสตริงนั้นคืออะไร ใน Codelab ส่วนใหญ่ คุณจะต้องอ้างอิงรหัสโปรเจ็กต์ (โดยทั่วไปจะระบุเป็น PROJECT_ID) หากไม่ชอบรหัสที่สร้างขึ้น คุณอาจสร้างรหัสแบบสุ่มอีกรหัสหนึ่งได้ หรือคุณอาจลองใช้ชื่อของคุณเองและดูว่ามีชื่อนั้นหรือไม่ คุณจะเปลี่ยนแปลงรหัสนี้หลังจากขั้นตอนนี้ไม่ได้ และรหัสจะคงอยู่ตลอดระยะเวลาของโปรเจ็กต์
  • โปรดทราบว่ายังมีค่าที่ 3 ซึ่งคือหมายเลขโปรเจ็กต์ที่ API บางตัวใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับค่าทั้ง 3 นี้ได้ในเอกสารประกอบ
  1. จากนั้นคุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร/API ของ Cloud การทำตาม Codelab นี้จะไม่มีค่าใช้จ่ายมากนัก หรืออาจไม่มีค่าใช้จ่ายเลย หากต้องการปิดทรัพยากรเพื่อหลีกเลี่ยงการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ คุณสามารถลบทรัพยากรที่สร้างขึ้นหรือลบโปรเจ็กต์ได้ ผู้ใช้ Google Cloud รายใหม่มีสิทธิ์เข้าร่วมโปรแกรมช่วงทดลองใช้ฟรีมูลค่า$300 USD

Google Cloud Shell

แม้ว่าคุณจะใช้งาน Google Cloud จากแล็ปท็อปได้จากระยะไกล แต่ใน Codelab นี้เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์

เปิดใช้งาน Cloud Shell

  1. จาก Cloud Console ให้คลิกเปิดใช้งาน Cloud Shell 853e55310c205094.png

55efc1aaa7a4d3ad.png

หากคุณเริ่มใช้ Cloud Shell เป็นครั้งแรก คุณจะเห็นหน้าจอระดับกลางที่อธิบายว่า Cloud Shell คืออะไร หากเห็นหน้าจอระดับกลาง ให้คลิกต่อไป

9c92662c6a846a5c.png

การจัดสรรและเชื่อมต่อกับ Cloud Shell จะใช้เวลาไม่นาน

9f0e51b578fecce5.png

เครื่องเสมือนนี้โหลดเครื่องมือพัฒนาซอฟต์แวร์ทั้งหมดที่จำเป็นไว้แล้ว โดยมีไดเรกทอรีหลักแบบถาวรขนาด 5 GB และทำงานใน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก คุณสามารถทำงานส่วนใหญ่หรือทั้งหมดในโค้ดแล็บนี้ได้ด้วยเบราว์เซอร์

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว คุณควรเห็นว่าคุณได้รับการตรวจสอบสิทธิ์และระบบได้ตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์ของคุณ

  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว
gcloud auth list

เอาต์พุตของคำสั่ง

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้จักโปรเจ็กต์ของคุณ
gcloud config list project

เอาต์พุตของคำสั่ง

[core]
project = <PROJECT_ID>

หากไม่ได้ตั้งค่าไว้ คุณตั้งค่าได้ด้วยคำสั่งนี้

gcloud config set project <PROJECT_ID>

เอาต์พุตของคำสั่ง

Updated property [core/project].

3. จัดสรรทรัพยากร Pub/Sub

ไปที่หน้าหัวข้อ Google Cloud Pub/Sub

คลิกสร้างหัวข้อ

4c938409dc7169a6.png

พิมพ์ exampleTopic เป็นชื่อหัวข้อ แล้วคลิกสร้าง

e2daeec91537f672.png

หลังจากสร้างหัวข้อแล้ว ให้อยู่ในหน้าหัวข้อ มองหาหัวข้อที่คุณเพิ่งสร้าง กดจุดแนวตั้ง 3 จุดที่ท้ายบรรทัด แล้วคลิกการติดตามใหม่

975efa26e5054936.png

พิมพ์ exampleSubscription ในกล่องข้อความชื่อการสมัครใช้บริการ แล้วคลิกสร้าง

f7a91d9e1cb48009.png

4. เริ่มต้นแอปพลิเคชัน Spring Boot

หลังจากเปิดใช้ Cloud Shell แล้ว คุณสามารถใช้บรรทัดคำสั่งเพื่อสร้างแอปพลิเคชัน Spring Boot ใหม่ 2 รายการด้วย 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. สร้างแอปพลิเคชันเพื่อส่งข้อความ

ตอนนี้เรามาสร้างแอปส่งข้อความกัน เปลี่ยนไปที่ไดเรกทอรีของแอปส่ง

$ cd spring-integration-sender

เราต้องการให้แอปเขียนข้อความไปยังช่อง หลังจากข้อความอยู่ในแชแนลแล้ว อะแดปเตอร์แชแนลขาออกจะรับข้อความดังกล่าว ซึ่งจะแปลงจากข้อความ Spring ทั่วไปเป็นข้อความ Google Cloud Pub/Sub และเผยแพร่ไปยังหัวข้อ Google Cloud Pub/Sub

หากต้องการให้แอปเขียนไปยังแชแนล เราสามารถใช้ Spring Integration messaging gateway ได้ ใช้โปรแกรมแก้ไขข้อความจาก vim, emacs หรือ nano เพื่อประกาศอินเทอร์เฟซ PubsubOutboundGateway ภายในคลาส 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);
  }
}

ตอนนี้เรามีกลไกในการส่งข้อความไปยังช่องแล้ว แต่ข้อความเหล่านั้นจะไปอยู่ที่ไหนหลังจากอยู่ในช่อง

เราต้องมีอะแดปเตอร์ช่องขาออกเพื่อใช้ข้อความใหม่ในช่องและเผยแพร่ไปยังหัวข้อ 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");
  }
}

คำอธิบายประกอบ @ServiceActivator จะทำให้ระบบใช้ MessageHandler นี้กับข้อความใหม่ใน inputChannel ในกรณีนี้ เราจะเรียกใช้ตัวดัดแปลงช่องขาออก PubSubMessageHandler เพื่อเผยแพร่ข้อความไปยังหัวข้อ exampleTopic ของ Google Cloud Pub/Sub

เมื่อมี Channel Adapter แล้ว ตอนนี้เราก็สามารถเชื่อมต่อออบเจ็กต์ PubsubOutboundGateway โดยอัตโนมัติและใช้เพื่อเขียนข้อความไปยังแชแนลได้

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("/");
  }
}

เนื่องจากมีคำอธิบายประกอบ @PostMapping ตอนนี้เราจึงมีปลายทางที่รับคำขอ HTTP POST แต่ก็ต้องเพิ่มคำอธิบายประกอบ @RestController ลงในคลาส DemoApplication เพื่อทำเครื่องหมายให้เป็นตัวควบคุม REST ด้วย

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

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

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

ตรวจสอบว่าได้ตั้งค่า JAVA_HOME เป็นเวอร์ชันที่ถูกต้อง

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

เรียกใช้แอปผู้ส่ง

# Set the Project ID in environmental variable
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format 'value(core.project)'`

$ ./mvnw spring-boot:run

แอปกำลังรอคำขอ POST ที่มีข้อความในพอร์ต 8080 และปลายทาง /postMessage แต่เราจะพูดถึงเรื่องนี้ในภายหลัง

6. สร้างแอปพลิเคชันเพื่อรับข้อความ

เราเพิ่งสร้างแอปที่ส่งข้อความผ่าน Google Cloud Pub/Sub ตอนนี้เราจะสร้างแอปอื่นที่รับข้อความเหล่านั้นและประมวลผล

คลิก + เพื่อเปิดเซสชัน Cloud Shell ใหม่

9799bee5fea95aa6.png

จากนั้นในเซสชัน Cloud Shell ใหม่ ให้เปลี่ยนไดเรกทอรีเป็นไดเรกทอรีของแอปตัวรับโดยใช้คำสั่งต่อไปนี้

$ cd spring-integration-receiver

ในแอปเวอร์ชันก่อน การประกาศเกตเวย์การรับส่งข้อความจะสร้างช่องขาออกให้เรา เนื่องจากเราไม่ได้ใช้เกตเวย์การรับส่งข้อความเพื่อรับข้อความ เราจึงต้องประกาศ MessageChannel ของเราเองซึ่งเป็นที่ที่ข้อความขาเข้าจะมาถึง

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

เราจะต้องใช้อะแดปเตอร์ช่องขาเข้าเพื่อรับข้อความจาก Google Cloud Pub/Sub และส่งต่อข้อความไปยัง 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;
  }
}

อแดปเตอร์นี้จะเชื่อมโยงตัวเองกับ pubsubInputChannel และรอรับข้อความใหม่จากการสมัครใช้บริการ exampleSubscription ของ Google Cloud Pub/Sub

เรามีช่องที่ใช้โพสต์ข้อความขาเข้า แต่จะทำอย่างไรกับข้อความเหล่านั้น

มาประมวลผลด้วย @ServiceActivator ที่จะทริกเกอร์เมื่อมีข้อความใหม่เข้ามาที่ 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);
  }
}

ตรวจสอบว่าได้ตั้งค่า JAVA_HOME เป็นเวอร์ชันที่ถูกต้อง

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

เรียกใช้แอปตัวรับ

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

ตอนนี้ระบบจะบันทึกข้อความที่คุณส่งไปยังแอปผู้ส่งในแอปผู้รับ หากต้องการทดสอบ ให้เปิดเซสชัน Cloud Shell ใหม่และส่งคำขอ HTTP POST ไปยังแอปผู้ส่ง

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

จากนั้นตรวจสอบว่าแอปผู้รับบันทึกข้อความที่คุณส่งแล้ว

INFO: Message arrived! Payload: Hello world!

7. ล้างข้อมูล

ลบการสมัครใช้บริการและหัวข้อที่สร้างขึ้นเป็นส่วนหนึ่งของการออกกำลังกายนี้

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

8. สรุป

คุณตั้งค่าแอป Spring Boot 2 แอปที่ใช้ Spring Integration Channel Adapters สำหรับ Google Cloud Pub/Sub โดยจะแลกเปลี่ยนข้อความกันเองโดยไม่ต้องโต้ตอบกับ Google Cloud Pub/Sub API

9. ยินดีด้วย

คุณได้เรียนรู้วิธีใช้ Spring Integration Channel Adapters สำหรับ Google Cloud Pub/Sub แล้ว

ดูข้อมูลเพิ่มเติม

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้สัญญาอนุญาตครีเอทีฟคอมมอนส์สำหรับยอมรับสิทธิของผู้สร้าง (Creative Commons Attribution License) 2.0 แบบทั่วไป