Messaging mit Spring Integration und Google Cloud Pub/Sub

Spring Integration bietet einen Messaging-Mechanismus zum Austausch von Messages über MessageChannels. Für die Kommunikation mit externen Systemen werden Kanaladapter verwendet.

In dieser Übung erstellen wir zwei Anwendungen, die über die von Spring Cloud GCP bereitgestellten Spring Integration-Kanaladapter kommunizieren. Mit diesen Adaptern wird Google Cloud Pub/Sub als Back-End für den Nachrichtenaustausch in Spring Integration verwendet.

Außerdem lernen Sie, wie Sie Cloud Shell und den Cloud SDK-Befehl "gcloud" verwenden.

In dieser Anleitung wird Beispielcode aus dem Spring Boot-Startleitfaden verwendet.

Lerninhalte

  • Nachrichten zwischen Apps mit Google Cloud Pub/Sub mithilfe von Spring Integration und Spring Cloud GCP austauschen

Voraussetzungen

  • Google Cloud Platform-Projekt
  • Ein Browser, z. B. Chrome oder Firefox
  • Erfahrung mit standardmäßigen Linux-Texteditoren wie Vim, EMACs oder Nano

Wie werden Sie diese Anleitung verwenden?

Nur lesen Lesen und Übungen durchführen

Wie würden Sie Ihre Erfahrung mit der Entwicklung von HTML/CSS-Web-Apps bewerten?

Anfänger Fortgeschrittene Experten

Wie würden Sie Ihre Erfahrungen mit der Verwendung von Google Cloud Platform-Diensten bewerten?

Anfänger Mittelstufe Fortgeschritten

Einrichtung der Umgebung im eigenen Tempo

Wenn Sie noch kein Google-Konto (Gmail oder Google Apps) haben, müssen Sie eins erstellen. Melden Sie sich in der Google Cloud Platform Console (console.cloud.google.com) an und erstellen Sie ein neues Projekt:

Screenshot vom 10.02.2016, 12:45:26.png

Notieren Sie sich die Projekt-ID, also den projektübergreifend nur einmal vorkommenden Namen eines Google Cloud-Projekts. Der oben angegebene Name ist bereits vergeben und kann leider nicht mehr verwendet werden. Sie wird in diesem Codelab später als PROJECT_ID bezeichnet.

Als Nächstes müssen Sie die Abrechnung in der Cloud Console aktivieren, um Google Cloud-Ressourcen verwenden zu können.

Dieses Codelab sollte Sie nicht mehr als ein paar Dollar kosten, aber es könnte mehr sein, wenn Sie sich für mehr Ressourcen entscheiden oder wenn Sie sie laufen lassen (siehe Abschnitt „Bereinigen“ am Ende dieses Dokuments).

Neuen Nutzern der Google Cloud Platform steht eine kostenlose Testversion mit einem Guthaben von 300$ zur Verfügung.

Google Cloud Shell

Während Sie Google Cloud von Ihrem Laptop aus per Fernzugriff nutzen können, wird in diesem Codelab Google Cloud Shell verwendet, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.

Google Cloud Shell aktivieren

Klicken Sie in der GCP Console oben rechts in der Symbolleiste auf das Cloud Shell-Symbol:

Klicken Sie dann auf "Cloud Shell starten":

Die Bereitstellung und Verbindung mit der Umgebung dauert nur einen Moment:

Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft auf der Google Cloud, wodurch Netzwerkleistung und Authentifizierung deutlich verbessert werden. Sie können die meisten, wenn nicht sogar alle Schritte in diesem Lab einfach mit einem Browser oder Ihrem Google Chromebook durchführen.

Sobald Sie mit Cloud Shell verbunden sind, sollten Sie sehen, dass Sie bereits authentifiziert sind und das Projekt bereits auf Ihre PROJECT_ID eingestellt ist.

Führen Sie in Cloud Shell den folgenden Befehl aus, um zu prüfen, ob Sie authentifiziert sind:

gcloud auth list

Befehlsausgabe

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Befehlsausgabe

[core]
project = <PROJECT_ID>

Ist dies nicht der Fall, können Sie die Einstellung mit diesem Befehl vornehmen:

gcloud config set project <PROJECT_ID>

Befehlsausgabe

Updated property [core/project].

Rufen Sie die Seite Google Cloud Pub/Sub-Themen auf und aktivieren Sie die API.

Klicken Sie auf Thema erstellen.

Geben Sie exampleTopic als Namen des Themas ein und klicken Sie dann auf Erstellen.

Bleiben Sie nach der Erstellung des Themas auf der Seite „Themen“. Suchen Sie nach dem gerade erstellten Thema, klicken Sie auf das Dreipunkt-Menü am Ende der Zeile und wählen Sie Neues Abo aus.

Geben Sie exampleSubscription in das Textfeld für den Abonnementsnamen ein und klicken Sie auf Erstellen.

Nachdem Cloud Shell gestartet wurde, können Sie über die Befehlszeile mit Spring Initializr zwei neue Spring Boot-Anwendungen generieren:

$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=2.0.6.RELEASE \
  -d dependencies=web \
  -d baseDir=spring-integration-sender | tar -xzvf -
$ curl https://start.spring.io/starter.tgz \
  -d bootVersion=2.0.6.RELEASE \
  -d baseDir=spring-integration-receiver | tar -xzvf -

Erstellen wir nun die App zum Senden von Nachrichten. Wechseln Sie in das Verzeichnis der Sende-App.

$ cd spring-integration-sender

Wir möchten, dass unsere App Nachrichten in einen Channel schreibt. Nachdem sich eine Nachricht im Kanal befindet, wird sie vom ausgehenden Kanaladapter abgeholt, der sie von einer generischen Spring-Nachricht in eine Google Cloud Pub/Sub-Nachricht konvertiert und in einem Google Cloud Pub/Sub-Thema veröffentlicht.

Damit unsere App in einen Kanal schreiben kann, können wir ein Spring Integration-Messaging-Gateway verwenden. Deklarieren Sie mit einem Texteditor aus vim, emacs oder nano eine PubsubOutboundGateway-Schnittstelle in der Klasse 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);
        }
}

Wir haben jetzt einen Mechanismus zum Senden von Nachrichten an einen Kanal. Aber was passiert mit diesen Nachrichten, nachdem sie im Kanal sind?

Wir benötigen einen Ausgangskanaladapter, um neue Nachrichten im Kanal zu verarbeiten und in einem Google Cloud Pub/Sub-Thema zu veröffentlichen.

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

...
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.cloud.gcp.pubsub.integration.outbound.PubSubMessageHandler;
import org.springframework.messaging.MessageHandler;

@SpringBootApplication
public class DemoApplication {

        ...

        @Bean
        @ServiceActivator(inputChannel = "pubsubOutputChannel")
        public MessageHandler messageSender(PubSubTemplate pubsubTemplate) {
                return new PubSubMessageHandler(pubsubTemplate, "exampleTopic");
        }
}

Durch die Anmerkung @ServiceActivator wird diese MessageHandler auf alle neuen Nachrichten in inputChannel angewendet. In diesem Fall rufen wir unseren Ausgangskanaladapter PubSubMessageHandler auf, um die Nachricht im exampleTopic-Thema von Google Cloud Pub/Sub zu veröffentlichen.

Nachdem der Kanaladapter eingerichtet ist, können wir jetzt ein PubsubOutboundGateway-Objekt automatisch einbinden und damit eine Nachricht in einen Kanal schreiben.

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

Dank der Annotation @PostMapping haben wir jetzt einen Endpunkt, der auf HTTP-POST-Anfragen wartet. Dazu muss jedoch auch der Klasse DemoApplication die Annotation @RestController hinzugefügt werden, um sie als REST-Controller zu kennzeichnen.

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

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

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

Damit die App ausgeführt werden kann, müssen wir nur die erforderlichen Abhängigkeiten hinzufügen.

pom.xml

<project>
  ...
  <!-- Add Spring Cloud GCP Dependency BOM -->
  <dependencyManagement>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-gcp-dependencies</artifactId>
                        <version>1.0.0.RELEASE</version>
                        <type>pom</type>
                        <scope>import</scope>
                </dependency>
        </dependencies>
  </dependencyManagement>

  <dependencies>
        ...
        <!-- Add Pub/Sub Starter -->
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
        </dependency>

        <!-- Add Spring Integration -->
        <dependency>
                <groupId>org.springframework.integration</groupId>
                <artifactId>spring-integration-core</artifactId>
        </dependency>

  </dependencies>

</project>

Führen Sie die Sender-App aus.

# Set the Project ID in environmental variable
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list \
  --format 'value(core.project)'`
$ ./mvnw spring-boot:run

Die App überwacht Port 8080 und den Endpunkt /postMessage auf POST-Anfragen mit einer Nachricht. Darauf gehen wir später noch ein.

Wir haben gerade eine App erstellt, die Nachrichten über Google Cloud Pub/Sub sendet. Als Nächstes erstellen wir eine weitere App, die diese Nachrichten empfängt und verarbeitet.

Klicken Sie auf +, um eine neue Cloud Shell-Sitzung zu öffnen.

Wechseln Sie dann in der neuen Cloud Shell-Sitzung in das Verzeichnis der Empfänger-App:

$ cd spring-integration-receiver

In der vorherigen App wurde durch die Deklaration des Messaging-Gateways der ausgehende Channel für uns erstellt. Da wir kein Messaging-Gateway zum Empfangen von Nachrichten verwenden, müssen wir unseren eigenen MessageChannel deklarieren, an dem eingehende Nachrichten eingehen.

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

Wir benötigen den Eingangskanaladapter, um Nachrichten von Google Cloud Pub/Sub zu empfangen und an pubsubInputChannel weiterzuleiten.

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

...
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate;
import org.springframework.cloud.gcp.pubsub.integration.inbound.PubSubInboundChannelAdapter;

@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;
        }
}

Dieser Adapter wird an pubsubInputChannel gebunden und wartet auf neue Nachrichten aus dem Google Cloud Pub/Sub-Abo exampleSubscription.

Wir haben einen Kanal, in dem eingehende Nachrichten gepostet werden. Was sollen wir mit diesen Nachrichten tun?

Lassen Sie uns sie mit einem @ServiceActivator verarbeiten, der ausgelöst wird, wenn neue Nachrichten bei pubsubInputChannel eingehen.

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

In diesem Fall protokollieren wir nur die Nutzlast der Nachricht.

Wir müssen die erforderlichen Abhängigkeiten hinzufügen.

pom.xml

<project>
  ...
  <!-- Add Spring Cloud GCP Dependency BOM -->
  <dependencyManagement>
        <dependencies>
                <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-gcp-dependencies</artifactId>
                        <version>1.0.0.RELEASE</version>
                        <type>pom</type>
                        <scope>import</scope>
                </dependency>
        </dependencies>
  </dependencyManagement>

  <dependencies>
        ...
        <!-- Add Pub/Sub Starter -->
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
        </dependency>

        <!-- Add Spring Integration -->
        <dependency>
                <groupId>org.springframework.integration</groupId>
                <artifactId>spring-integration-core</artifactId>
        </dependency>

  </dependencies>

</project>

Führen Sie die Empfänger-App aus.

$ ./mvnw spring-boot:run

Alle Nachrichten, die Sie an die Sender-App senden, werden nun in der Empfänger-App protokolliert. Öffnen Sie dazu eine neue Cloud Shell-Sitzung und senden Sie eine HTTP-POST-Anfrage an die Sender-App.

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

Prüfe dann, ob die Empfänger-App die von dir gesendete Nachricht protokolliert hat.

INFO: Message arrived! Payload: Hello world!

Löschen Sie das Abo und das Thema, die im Rahmen dieser Übung erstellt wurden.

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

Sie richten zwei Spring Boot-Apps ein, die die Spring Integration-Kanaladapter für Google Cloud Pub/Sub verwenden. Sie tauschen Nachrichten untereinander aus, ohne jemals mit der Google Cloud Pub/Sub API zu interagieren.

Sie haben gelernt, wie Sie die Spring Integration Channel Adapters für Google Cloud Pub/Sub verwenden.

Weitere Informationen

Lizenz

Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.