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

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

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

בתרגיל הזה ניצור שתי אפליקציות שמתקשרות באמצעות מתאמי הערוצים של 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,‏ EMACs או Nano

איך תשתמש במדריך הזה?

רק לקרוא לקרוא ולבצע את התרגילים

מה מידת שביעות הרצון שלך מחוויית השימוש ב-HTML/CSS ליצירת אפליקציות אינטרנט?

מתחילים ביניים מומחים

איזה דירוג מגיע לדעתך לחוויית השימוש שלך בשירותים של Google Cloud Platform?

מתחילים ביניים מומחים

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים ל-מסוף Google Cloud ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • שם הפרויקט הוא השם המוצג של הפרויקט הזה למשתתפים. זו מחרוזת תווים שלא נמצאת בשימוש ב-Google APIs. תמיד אפשר לעדכן את המיקום.
  • מזהה הפרויקט הוא ייחודי לכל הפרויקטים ב-Google Cloud, והוא קבוע (אי אפשר לשנות אותו אחרי שהוא מוגדר). מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית, ובדרך כלל לא צריך לדעת מה היא. ברוב ה-Codelabs, תצטרכו להפנות למזהה הפרויקט (בדרך כלל מסומן כ-PROJECT_ID). אם אתם לא אוהבים את המזהה שנוצר, אתם יכולים ליצור מזהה אקראי אחר. אפשר גם לנסות שם משתמש משלכם ולבדוק אם הוא זמין. אי אפשר לשנות את ההגדרה הזו אחרי השלב הזה, והיא תישאר לאורך הפרויקט.
  • לידיעתכם, יש ערך שלישי, מספר פרויקט, שחלק מממשקי ה-API משתמשים בו. במאמרי העזרה מפורט מידע נוסף על שלושת הערכים האלה.
  1. בשלב הבא, תצטרכו להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבי Cloud או בממשקי API של Cloud. השלמת ה-codelab הזה לא תעלה לכם הרבה, אם בכלל. כדי להשבית את המשאבים ולמנוע חיובים נוספים אחרי שתסיימו את המדריך הזה, תוכלו למחוק את המשאבים שיצרתם או למחוק את הפרויקט. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.

Google Cloud Shell

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

הפעלת Cloud Shell

  1. ב-Cloud Console, לוחצים על 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

אחרי שיוצרים את הנושא, נשארים בדף 'נושאים'. חפשו את הנושא שיצרתם, לחצו על שלוש הנקודות האנכיות בסוף השורה ואז על New Subscription (מינוי חדש).

975efa26e5054936.png

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

f7a91d9e1cb48009.png

4. אתחול אפליקציות Spring Boot

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

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

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 שמשתמשות במתאמי הערוצים של Spring Integration ל-Google Cloud Pub/Sub. הם מחליפים ביניהם הודעות בלי ליצור אינטראקציה עם Google Cloud Pub/Sub API.

9. מעולה!

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

מידע נוסף

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.