העברת הודעות באמצעות שילוב Spring עם Google Cloud Pub/Sub

1. סקירה כללית

השילוב של Spring מספק מנגנון להעברת הודעות שבאמצעותו אפשר להחליף את Messages דרך MessageChannels. הוא משתמש במתאמי ערוצים כדי לתקשר עם מערכות חיצוניות.

בתרגיל הזה ניצור שתי אפליקציות שמתקשרות באמצעות מתאמי הערוצים של Spring Integration שסופקו על ידי Spring Cloud GCP. המתאמים האלה גורמים לשילוב של Spring להשתמש ב-Google Cloud Pub/Sub בתור הקצה העורפי להחלפת הודעות.

תלמדו איך להשתמש ב-Cloud Shell ובפקודה Cloud SDK gcloud.

המדריך הזה משתמש בקוד לדוגמה מהמדריך לתחילת השימוש באתחול אביב.

מה תלמדו

  • איך מעבירים הודעות בין אפליקציות עם 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 ויוצרים פרויקט חדש או עושים שימוש חוזר בפרויקט קיים. אם אין לכם עדיין חשבון Gmail או חשבון Google Workspace, עליכם ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Project name הוא השם המוצג של המשתתפים בפרויקט. זו מחרוזת תווים שלא משמשת את Google APIs. תמיד אפשר לעדכן.
  • Project ID הוא ייחודי בכל הפרויקטים ב-Google Cloud ואי אפשר לשנות אותו (אי אפשר לשנות אותו אחרי שמגדירים אותו). מסוף Cloud יוצר מחרוזת ייחודית באופן אוטומטי; בדרך כלל לא מעניין אותך מה זה. ברוב ה-codelabs תצטרכו להפנות למזהה הפרויקט שלכם (בדרך כלל מזוהה כ-PROJECT_ID). אם המזהה שנוצר לא מוצא חן בעיניכם, אתם יכולים ליצור מזהה אקראי אחר. לחלופין, אפשר לנסות שם משלך ולראות אם הוא זמין. לא ניתן לשנות אותו אחרי השלב הזה, והוא נשאר למשך הפרויקט.
  • לידיעתך, יש ערך שלישי, Project Number, שבו משתמשים בחלק מממשקי ה-API. מידע נוסף על כל שלושת הערכים האלה זמין במסמכי התיעוד.
  1. בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים או בממשקי API של Cloud. מעבר ב-Codelab הזה לא יעלה הרבה כסף, אם בכלל. כדי להשבית משאבים ולא לצבור חיובים מעבר למדריך הזה, אתם יכולים למחוק את המשאבים שיצרתם או למחוק את הפרויקט. משתמשים חדשים ב-Google Cloud זכאים להשתתף בתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.

Google Cloud Shell

אומנם אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-Codelab הזה נשתמש ב-Google Cloud Shell, סביבת שורת הפקודה שפועלת ב-Cloud.

הפעלת Cloud Shell

  1. במסוף Cloud, לוחצים על Activate Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג לכם מסך ביניים שמתאר מהו. אם הוצג לכם מסך ביניים, לוחצים על המשך.

9c92662c6a846a5c.png

ההקצאה וההתחברות ל-Cloud Shell נמשכת כמה דקות.

9f0e51b578fecce5.png

במכונה הווירטואלית הזו נמצאים כל כלי הפיתוח הדרושים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. אם לא את כולן, ניתן לבצע חלק גדול מהעבודה ב-Codelab הזה באמצעות דפדפן.

אחרי ההתחברות ל-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

אחרי שהנושא נוצר, נשארים בדף Topics (נושאים). מחפשים את הנושא שיצרתם, לוחצים על שלוש הנקודות במאונך שבסוף השורה ולוחצים על מינוי חדש.

975efa26e5054936.png

מקלידים exampleSubscription בתיבת הטקסט של שם המינוי ולוחצים על יצירה.

f7a91d9e1cb48009.png

4. אתחול אפליקציות אתחול קפיצים

אחרי ההשקה של Cloud Shell, תוכלו להשתמש בשורת הפקודה כדי ליצור שתי אפליקציות חדשות ל-Springboot באמצעות 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. אם משתמשים בכלי לעריכת טקסט מ-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.

כשמתאם הערוץ נמצא, עכשיו אפשר לחבר באופן אוטומטי אובייקט 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, עכשיו יש לנו נקודת קצה (endpoint) שמאזינים לבקשות 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. במקרה כזה, נרשום ביומן את המטען הייעודי (Payload) של ההודעה.

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. סיכום

הגדרתם שתי אפליקציות Springboos שבהן נעשה שימוש במתאמי הערוצים לשילוב Spring עבור Google Cloud Pub/Sub. הם מחליפים ביניהם הודעות בלי כל אינטראקציה עם Google Cloud Pub/Sub API.

9. מעולה!

למדת איך להשתמש במתאמי ערוצי השילוב של Spring עבור Google Cloud Pub/Sub!

מידע נוסף

רישיון

היצירה הזו בשימוש ברישיון Creative Commons Attribution 2.0 גנרי.