المراسلة من خلال Spring Integration و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 Console وأنشئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

b35bf95b8bf3d5d8.pnga99b7ace416376c4.pngbd84a6d3004737c5.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهو عبارة عن سلسلة أحرف لا تستخدمها Google APIs. يمكنك تعديله في أي وقت.
  • رقم تعريف المشروع فريد بين جميع مشاريع Google Cloud ولا يمكن تغييره (لا يمكن تغييره بعد ضبطه). تنشئ Cloud Console تلقائيًا سلسلة فريدة، ولا يهمّك عادةً ما هي. في معظم الدروس التطبيقية حول الترميز، عليك الرجوع إلى رقم تعريف مشروعك (يُشار إليه عادةً باسم PROJECT_ID). إذا لم يعجبك رقم التعريف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. بدلاً من ذلك، يمكنك تجربة رقم تعريف خاص بك ومعرفة ما إذا كان متاحًا. لا يمكن تغييره بعد هذه الخطوة ويظل ساريًا طوال مدة المشروع.
  • للعلم، هناك قيمة ثالثة، وهي رقم المشروع، تستخدمها بعض واجهات برمجة التطبيقات. يمكنك الاطّلاع على مزيد من المعلومات عن هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد/واجهات برمجة تطبيقات Cloud. لن يكلفك إكمال هذا الدرس التطبيقي حول الترميز الكثير من المال، إن وُجدت أي تكلفة على الإطلاق. لإيقاف الموارد وتجنُّب تحمُّل رسوم فوترة تتجاوز هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع. يمكن لمستخدمي Google Cloud الجدد الاستفادة من برنامج التجربة المجانية بقيمة 300 دولار أمريكي.

Google Cloud Shell

على الرغم من إمكانية تشغيل Google Cloud عن بُعد من جهاز الكمبيوتر المحمول، سنستخدم في هذا الدرس التطبيقي حول الترميز Google Cloud Shell، وهي بيئة سطر أوامر تعمل في السحابة الإلكترونية.

تفعيل Cloud Shell

  1. من Cloud Console، انقر على تفعيل Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

إذا كانت هذه هي المرة الأولى التي تبدأ فيها Cloud Shell، ستظهر لك شاشة وسيطة تصف هذه البيئة. إذا ظهرت لك شاشة وسيطة، انقر على متابعة.

9c92662c6a846a5c.png

لن يستغرق توفير Cloud Shell والاتصال به سوى بضع لحظات.

9f0e51b578fecce5.png

تحتوي هذه الآلة الافتراضية على جميع أدوات التطوير اللازمة. وتوفّر دليلًا رئيسيًا دائمًا بسعة 5 غيغابايت وتعمل في 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

بعد إنشاء الموضوع، ابقَ في صفحة "المواضيع". ابحث عن الموضوع الذي أنشأته للتو، وانقر على النقاط العمودية الثلاث في نهاية السطر، ثم انقر على اشتراك جديد.

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. باستخدام محرّر نصوص من 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، لدينا الآن نقطة نهاية تستمع إلى طلبات 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.

مزيد من المعلومات

الترخيص

يخضع هذا العمل لترخيص المشاع الإبداعي 2.0 العام مع نسب العمل إلى مؤلفه.