Messaging mit Spring-Integration und Google Cloud Pub/Sub

Spring Integration bietet einen Mechanismus, über den du Messages bis MessageChannels austauschen kannst. Für die Kommunikation mit externen Systemen werden Kanaladapter verwendet.

In dieser Übung werden zwei Apps erstellt, die über die von Spring Cloud GCP bereitgestellten Kanaladapter kommunizieren. Durch diese Adapter nutzen Spring Integrations Google Cloud Pub/Sub als Nachrichtenaustausch-Back-End.

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

In dieser Anleitung wird der Beispielcode aus der Anleitung zum Einstieg in Spring Boot verwendet.

Lerninhalte

  • Mit Spring-Integration und Spring Cloud GCP Nachrichten zwischen Anwendungen mit Google Cloud Pub/Sub austauschen

Voraussetzungen

  • Google Cloud Platform-Projekt
  • Ein Browser, wie Chrome oder Firefox
  • Kenntnisse in standardmäßigen Linux-Texteditoren wie Vim, EMACs oder Nano

Wie werden Sie diese Anleitung verwenden?

Nur Lesen Gelesen und die Übungen abschließen

Wie würdest du deine Erfahrung beim Erstellen von HTML-/CSS-Webanwendungen bewerten?

Neuling Fortgeschritten Profi

Wie würdest du deine Erfahrung mit der Nutzung der Google Cloud Platform-Dienste bewerten?

Fortgeschritten Fortgeschritten Profi

Umgebung im eigenen Tempo einrichten

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

Screenshot von 2016-02-10 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. In diesem Codelab wird sie später als PROJECT_ID bezeichnet.

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

Das Durchlaufen dieses Codelabs sollte nicht mehr als ein paar Dollar kosten. Es kann aber auch sein, dass Sie mehr Ressourcen brauchen oder sie weiterlaufen möchten (siehe Abschnitt „Bereinigen“ am Ende dieses Dokuments).

Neuen Google Cloud Platform-Nutzern steht ein kostenloser Testzeitraum im Wert von 300$ zur Verfügung.

Google Cloud Shell

Google Cloud kann aus der Ferne über Ihren Laptop ausgeführt werden. In diesem Codelab nutzen wir Google Cloud Shell, 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 dass das Projekt auf Ihre PROJECT_ID festgelegt ist.

Führen Sie in Cloud Shell den folgenden Befehl aus, um zu bestätigen, dass 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 Google Cloud Pub/Sub-Themenseite 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 dem Erstellen des Themas auf der Seite „Themen“. Suche nach dem Thema, das du gerade erstellt hast. Klicke am Ende der Zeile auf das Dreipunkt-Menü und klicke auf Neues Abo.

Geben Sie in das Textfeld „Aboname“ exampleSubscription ein und klicken Sie auf Erstellen.

Nach dem Start von Cloud Shell können Sie über die Befehlszeile zwei neue Spring-Boot-Anwendungen mit Spring Initializr 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 -

Jetzt erstellen wir unsere App zum Senden von Nachrichten. Wechseln Sie zum Verzeichnis der sendenden App.

$ cd spring-integration-sender

Wir möchten, dass unsere App Nachrichten auf einem Kanal schreibt. Sobald sich eine Nachricht im Kanal befindet, wird sie vom Adapter für ausgehende Kanäle abgerufen, der sie von einer allgemeinen Spring-Nachricht in eine Google Cloud Pub/Sub-Nachricht konvertiert und in einem Google Cloud Pub/Sub-Thema veröffentlicht.

Damit unsere App auf einen Kanal schreiben kann, können wir ein Gateway für Nachrichten von Spring Integration verwenden. Deklarieren Sie mit einem Texteditor aus vim, emacs oder nano eine PubsubOutboundGateway-Schnittstelle innerhalb der DemoApplication-Klasse.

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

Es gibt jetzt eine Möglichkeit, Nachrichten an einen Kanal zu senden. Wohin gelangen die Nachrichten, wenn sie auf dem 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");
        }
}

Die Annotation @ServiceActivator führt dazu, dass dieses MessageHandler auf neue Nachrichten in inputChannel angewendet wird. In diesem Fall rufen wir den externen Kanaladapter PubSubMessageHandler auf, um die Nachricht in dem exampleTopic-Thema von Google Cloud Pub/Sub zu veröffentlichen.

Wenn der Kanaladapter eingerichtet ist, können wir jetzt ein PubsubOutboundGateway-Objekt automatisch verkabeln und damit eine Nachricht an 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("/");
        }
}

Aufgrund der Annotation @PostMapping haben wir jetzt einen Endpunkt, der HTTP-POST-Anfragen überwacht, jedoch nicht ohne die @RestController-Annotation zur DemoApplication-Klasse hinzuzufügen, 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 Anwendung ausgeführt werden kann, müssen Sie 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 Absender-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 wartet auf POST-Anfragen, die eine Nachricht an Port 8080 und den Endpunkt /postMessage enthalten. Darauf gehen wir später noch ein.

Wir haben gerade eine App erstellt, die Nachrichten über Google Cloud Pub/Sub sendet. Jetzt 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 zum Verzeichnis der Empfängeranwendung:

$ cd spring-integration-receiver

In der bisherigen App wurde der Ausgangskanal durch das Messaging-Gateway deklariert. Da wir kein Messaging-Gateway für den Empfang von Nachrichten verwenden, müssen wir unser eigenes MessageChannel-Element deklarieren, das eingehende Daten erhält.

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 eingehenden Kanaladapter, 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 verbindet sich mit der pubsubInputChannel und hört neue Nachrichten aus dem Google Cloud Pub/Sub exampleSubscription-Abo ab.

Wir haben einen Kanal, auf dem eingehende Nachrichten gepostet werden. Aber was macht man damit?

Sie werden mit einem @ServiceActivator verarbeitet, der ausgelöst wird, wenn neue Nachrichten in pubsubInputChannel ankommen.

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 wird nur die Nutzlast der Nachricht protokolliert.

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

Jetzt werden alle Nachrichten, die Sie an die Absender-App senden, in der Empfänger-App protokolliert. Sie können das testen, indem Sie eine neue Cloud Shell-Sitzung öffnen und eine HTTP-POST-Anfrage an die Absender-App senden.

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

Prüfen Sie dann, ob in der Empfänger-App die Nachricht protokolliert wurde.

INFO: Message arrived! Payload: Hello world!

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

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

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

Sie haben gelernt, wie Sie die Spring-Integrationskanaladapter für Google Cloud Pub/Sub verwenden.

Weitere Informationen

Lizenz

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