المراسلة من خلال 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.png

a99b7ace416376c4.png

bd84a6d3004737c5.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 Channel Adapters لخدمة Google Cloud Pub/Sub. ويتبادلون الرسائل فيما بينهم بدون التفاعل مع واجهة برمجة التطبيقات Google Cloud Pub/Sub.

9- تهانينا!

تعرّفت على كيفية استخدام "محوّلات قنوات Spring Integration" في Google Cloud Pub/Sub.

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

الترخيص

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