Messagerie avec l'intégration de Spring et Google Cloud Pub/Sub

L'intégration de Spring fournit un mécanisme de messagerie pour échanger Messages via MessageChannels. Il utilise des adaptateurs de canaux pour communiquer avec des systèmes externes.

Dans cet exercice, nous allons créer deux applications qui communiquent à l'aide des adaptateurs de canaux Spring Integration fournis par Spring Cloud GCP. Ces adaptateurs permettent à Spring Integration d'utiliser Google Cloud Pub/Sub comme backend d'échange de messages.

Vous découvrirez aussi comment utiliser Cloud Shell et la commande gcloud du SDK Cloud.

Ce tutoriel utilise l'exemple de code du guide de démarrage de Spring Boot.

Points abordés

  • Échanger des messages entre les applications avec Google Cloud Pub/Sub à l'aide de Spring Integration et de Spring Cloud GCP

Prérequis

  • Un projet Google Cloud Platform
  • Un navigateur tel que Chrome ou Firefox
  • Bonne connaissance des éditeurs de texte Linux standards tels que Vim, EMACs ou Nano

Comment allez-vous utiliser ce tutoriel ?

Je vais le lire uniquement Je vais le lire et effectuer les exercices

Comment évalueriez-vous votre niveau en matière de création d'applications Web HTML/CSS ?

Débutant Intermédiaire Expert

Quel est votre niveau d'expérience avec les services Google Cloud Platform ?

Débutant Intermédiaire Compétent

Configuration de l'environnement au rythme de chacun

Si vous n'avez pas encore de compte Google (Gmail ou Google Apps), vous devez en créer un. Connectez-vous à la console Google Cloud Platform (console.cloud.google.com) et créez un projet:

Capture d'écran du 10/02/2016 12:45:26.png

Mémorisez l'ID du projet. Il s'agit d'un nom unique permettant de différencier chaque projet Google Cloud (le nom ci-dessus est déjà pris ; vous devez en trouver un autre). Il sera désigné par le nom PROJECT_ID tout au long de cet atelier de programmation.

Vous devez ensuite activer la facturation dans Cloud Console afin d'utiliser les ressources Google Cloud.

Suivre cet atelier de programmation ne devrait pas vous coûter plus d'un euro. Cependant, cela peut s'avérer plus coûteux si vous décidez d'utiliser davantage de ressources ou si vous n'interrompez pas les ressources (voir la section "Effectuer un nettoyage" à la fin du présent document).

Les nouveaux utilisateurs de Google Cloud Platform peuvent bénéficier d'un essai offert de 300 $.

Google Cloud Shell

Vous pouvez utiliser Google Cloud à distance depuis votre ordinateur portable. Dans cet atelier de programmation, nous utiliserons Google Cloud Shell, un environnement de ligne de commande fonctionnant dans le cloud.

Activer Google Cloud Shell

Depuis la console GCP, cliquez sur l'icône Cloud Shell de la barre d'outils située dans l'angle supérieur droit :

Cliquez ensuite sur "Démarrer Cloud Shell" :

Le provisionnement de l'environnement et la connexion ne devraient pas prendre plus de quelques minutes :

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle intègre un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez réaliser une grande partie, voire la totalité, des activités de cet atelier dans un simple navigateur ou sur votre Chromebook Google.

En principe, une fois que vous êtes connecté à Cloud Shell, vous êtes authentifié, et le projet est défini sur PROJECT_ID.

Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :

gcloud auth list

Résultat de la commande

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

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

Accédez à la page des sujets Google Cloud Pub/Sub et activez l'API.

Cliquez sur Créer un sujet.

Saisissez exampleTopic comme nom du sujet, puis cliquez sur Create (Créer).

Une fois le sujet créé, restez sur la page "Sujets". Recherchez le sujet que vous venez de créer, appuyez sur les trois points verticaux à la fin de la ligne, puis cliquez sur Nouvel abonnement.

Saisissez exampleSubscription dans la zone de texte du nom de l'abonnement, puis cliquez sur Créer.

Après le lancement de Cloud Shell, vous pouvez utiliser la ligne de commande pour générer deux nouvelles applications Spring Boot avec Spring Initializr:

$ 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 -

Créons maintenant notre application d'envoi de messages. Accédez au répertoire de l'application d'envoi.

$ cd spring-integration-sender

Nous voulons que notre application puisse écrire des messages sur une chaîne. Une fois qu'un message est dans le canal, il est récupéré par l'adaptateur de canal sortant, qui le convertit d'un message Spring générique en message Google Cloud Pub/Sub, puis le publie sur un sujet Google Cloud Pub/Sub.

Pour que notre application puisse écrire sur une chaîne, nous pouvons utiliser une passerelle de messagerie d'intégration de printemps. À l'aide d'un éditeur de texte de vim, emacs ou nano, déclarez une interface PubsubOutboundGateway dans la classe 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);
        }
}

Nous disposons à présent d'un mécanisme qui permet d'envoyer des messages à une chaîne. Mais où sont placés ces messages une fois qu'ils ont été publiés sur la chaîne ?

Nous avons besoin d'un adaptateur de canal sortant pour consommer les nouveaux messages dans le canal et les publier dans un sujet Google Cloud Pub/Sub.

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

L'annotation @ServiceActivator entraîne l'application de cet MessageHandler à tous les nouveaux messages de inputChannel. Dans le cas présent, nous appelons notre adaptateur de canal sortant, PubSubMessageHandler, pour publier le message sur le sujet exampleTopic Google Cloud Pub/Sub.

Une fois l'adaptateur de chaîne en place, nous pouvons alimenter automatiquement un objet PubsubOutboundGateway et l'utiliser pour écrire un message sur un canal.

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

En raison de l'annotation @PostMapping, nous disposons désormais d'un point de terminaison qui écoute les requêtes HTTP POST, mais pas sans ajouter une annotation @RestController à la classe DemoApplication pour le marquer comme contrôleur REST.

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

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

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

Pour que l'application s'exécute, il suffit d'ajouter les dépendances requises.

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>

Exécutez l'application émettrice.

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

L'application écoute les requêtes POST contenant un message sur le port 8080 et le point de terminaison /postMessage, mais nous y reviendrons plus tard.

Nous venons de créer une application qui envoie des messages via Google Cloud Pub/Sub. Nous allons maintenant créer une autre application qui reçoit ces messages et les traite.

Cliquez sur + pour ouvrir une nouvelle session Cloud Shell.

Ensuite, dans la nouvelle session Cloud Shell, remplacez les répertoires par le répertoire de l'application réceptrice:

$ cd spring-integration-receiver

Dans l'application précédente, la déclaration de la passerelle de messagerie avait créé le canal sortant. Étant donné que nous n'utilisons pas de passerelle de messagerie pour recevoir les messages, nous devons déclarer notre propre MessageChannel permettant de recevoir les messages entrants.

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

Nous aurons besoin de l'adaptateur de canal entrant pour recevoir les messages de Google Cloud Pub/Sub et les transmettre à pubsubInputChannel.

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

Cet adaptateur s'associe à pubsubInputChannel et écoute les nouveaux messages provenant de l'abonnement exampleSubscription de Google Cloud Pub/Sub.

Vous disposez d'une chaîne sur laquelle les messages entrants sont publiés, mais comment les traiter ?

Traitement des données par un @ServiceActivator déclenché lorsque de nouveaux messages arrivent à 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);
        }
}

Dans ce cas, nous nous contentons de consigner la charge utile du message.

Nous devons ajouter les dépendances nécessaires.

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>

Exécutez l'application réceptrice.

$ ./mvnw spring-boot:run

Désormais, tous les messages que vous envoyez à l'application émettrice seront enregistrés dans l'application réceptrice. Pour effectuer un test, ouvrez une nouvelle session Cloud Shell et envoyez une requête HTTP POST à l'application émettrice.

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

Vérifiez ensuite que l'application réceptrice a enregistré le message que vous avez envoyé.

INFO: Message arrived! Payload: Hello world!

Supprimez l'abonnement et le sujet créés dans le cadre de cet exercice.

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

Vous configurez deux applications Spring Boot qui utilisent les adaptateurs de canal d'intégration Spring pour Google Cloud Pub/Sub. Ils échangent des messages entre eux sans interagir avec l'API Google Cloud Pub/Sub.

Vous avez appris à utiliser les adaptateurs de canaux d'intégration de Spring InStream pour Google Cloud Pub/Sub.

En savoir plus

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.