Messaggistica con Spring Integration e Google Cloud Pub/Sub

L'integrazione di primavera ti offre un meccanismo di messaggistica per scambiare Messages tramite MessageChannels. Utilizza gli adattatori dei canali per comunicare con i sistemi esterni.

In questo esercizio creeremo due app che comunicano tramite gli adattatori dei canali di integrazione di Spring forniti da Spring Cloud GCP. Questi adattatori utilizzano l'integrazione di primavera in Google Cloud Pub/Sub come backend di scambio di messaggi.

Imparerai a utilizzare Cloud Shell e il comando gcloud di Cloud SDK.

Questo tutorial utilizza il codice di esempio della guida introduttiva a Spring Boot.

Cosa imparerai a fare:

  • Come scambiare messaggi tra le app con Google Cloud Pub/Sub utilizzando Spring Integration e Spring Cloud GCP

Che cosa ti serve

  • Un progetto Google Cloud Platform
  • Un browser, come Chrome o Firefox
  • Familiarità con gli editor di testo standard di Linux, ad esempio Vim, EMAC o Nano

Come utilizzerai questo tutorial?

Leggilo solo Leggilo e completa gli esercizi

Come valuteresti la tua esperienza con la creazione di app web HTML/CSS?

Principiante Intermedio Esperto

Come giudichi la tua esperienza con l'utilizzo dei servizi Google Cloud Platform?

Principiante Intermedio Esperto

Configurazione automatica dell'ambiente

Se non hai ancora un Account Google (Gmail o Google Apps), devi crearne uno. Accedi alla console di Google Cloud Platform (console.cloud.google.com) e crea un nuovo progetto.

Screenshot dal 10/02/2016 alle 00:45:26.png

Ricorda l'ID progetto, un nome univoco in tutti i progetti Google Cloud (il nome sopra riportato è già stato utilizzato e non funzionerà per te). Vi verrà fatto riferimento più avanti in questo codelab come PROJECT_ID.

Il prossimo passaggio consiste nell'attivare la fatturazione in Cloud Console per utilizzare le risorse di Google Cloud.

L'esecuzione di questo codelab non dovrebbe costare più di qualche euro, ma potrebbe essere di più se decidi di utilizzare più risorse o se le lasci in esecuzione (vedi la sezione "pulizia" alla fine di questo documento).

I nuovi utenti di Google Cloud Platform sono idonei per una prova senza costi di 300 $.

Google Cloud Shell

Sebbene Google Cloud possa essere gestito da remoto dal tuo laptop, in questo codelab utilizzeremo Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.

Attiva Google Cloud Shell

Nella console di GCP, fai clic sull'icona di Cloud Shell nella barra degli strumenti in alto a destra:

Quindi fai clic su "Start Cloud Shell":

Bastano pochi istanti per eseguire il provisioning e connettersi all'ambiente:

Questa macchina virtuale è dotata di tutti gli strumenti di sviluppo di cui hai bisogno. Offre una home directory permanente da 5 GB e viene eseguita su Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Gran parte del lavoro in questo lab, se non tutto, può essere svolto semplicemente con un browser o con Google Chromebook.

Una volta connesso a Cloud Shell, dovresti vedere che sei già autenticato e che il progetto è già impostato sul tuo PROJECT_ID.

Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:

gcloud auth list

Output comando

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

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

Vai alla pagina degli argomenti Google Cloud Pub/Sub e attiva l'API.

Fai clic su Crea argomento.

Digita exampleTopic come nome dell'argomento, quindi fai clic su Crea.

Dopo aver creato l'argomento, rimani nella pagina Argomenti. Cerca l'argomento appena creato, premi i tre puntini verticali alla fine della riga e fai clic su Nuovo abbonamento.

Digita exampleSubscription nella casella di testo del nome dell'abbonamento e fai clic su Crea.

Una volta avviato Cloud Shell, puoi utilizzare la riga di comando per generare due nuove applicazioni Spring Boot con 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 -

Ora creiamo la nostra app di invio dei messaggi. Passa alla directory dell'app di invio.

$ cd spring-integration-sender

Vogliamo che la nostra app scriva messaggi in un canale. Dopo che un messaggio è stato inserito nel canale, verrà recuperato dall'adattatore del canale in uscita, che lo converte da un messaggio Spring generico a un messaggio Google Cloud Pub/Sub e lo pubblica in un argomento Google Cloud Pub/Sub.

Per consentire alla nostra app di scrivere su un canale, possiamo utilizzare un gateway di messaggistica di integrazione di primavera. Utilizzando un editor di testo da vim, emacs o nano, dichiara un'interfaccia di PubsubOutboundGateway all'interno della 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);
        }
}

Ora abbiamo un meccanismo per inviare messaggi a un canale, ma dove si trovano i messaggi dopo che si trovano nel canale?

Occorre un adattatore del canale in uscita per consumare nuovi messaggi nel canale e pubblicarli in un argomento di 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'annotazione @ServiceActivator fa sì che questo MessageHandler venga applicato a tutti i nuovi messaggi in inputChannel. In questo caso, stiamo chiamando il nostro adattatore per il canale in uscita, PubSubMessageHandler, per pubblicare il messaggio nell'argomento exampleTopic di Google Cloud Pub/Sub.

Ora che l'adattatore del canale è pronto, possiamo collegare automaticamente un oggetto PubsubOutboundGateway e utilizzarlo per scrivere un messaggio su un canale.

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

A causa dell'annotazione @PostMapping, ora è disponibile un endpoint che ascolta le richieste POST HTTP, ma non è necessario aggiungere un'annotazione @RestController alla classe DemoApplication per contrassegnarla come controller REST.

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

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

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

Per poter eseguire l'app, basta aggiungere le dipendenze richieste.

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>

Esegui l'app del mittente.

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

L'app è in ascolto delle richieste POST contenenti un messaggio sulla porta 8080 e sull'endpoint /postMessage, ma ci occuperemo in seguito.

Abbiamo appena creato un'app che invia i messaggi tramite Google Cloud Pub/Sub. Ora creeremo un'altra app che riceverà i messaggi e li elaborerà.

Fai clic su + per aprire una nuova sessione di Cloud Shell.

Quindi, nella nuova sessione di Cloud Shell, modifica le directory nella directory dell'app del destinatario:

$ cd spring-integration-receiver

Nell'app precedente, la dichiarazione del gateway di messaggistica ha creato per noi il canale in uscita. Poiché non utilizziamo un gateway di messaggistica per ricevere messaggi, dobbiamo dichiarare il nostro MessageChannel in cui verranno ricevuti i messaggi in arrivo.

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

Abbiamo bisogno dell'adattatore del canale in entrata per ricevere i messaggi da Google Cloud Pub/Sub e inoltrarli a 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;
        }
}

Questo adattatore si associa al pubsubInputChannel e ascolta i nuovi messaggi dall'abbonamento a Google Cloud Pub/Sub exampleSubscription.

Abbiamo un canale su cui vengono pubblicati i messaggi in arrivo, ma come si fa con questi messaggi?

Li elaboriamo con un @ServiceActivator che viene attivato quando arrivano nuovi messaggi a 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);
        }
}

In questo caso, registriamo semplicemente il payload del messaggio.

Dobbiamo aggiungere le dipendenze necessarie.

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>

Esegui l'app del ricevitore.

$ ./mvnw spring-boot:run

Ora tutti i messaggi che invii all'app del mittente verranno registrati nell'app del destinatario. Per testarlo, apri una nuova sessione di Cloud Shell ed effettua una richiesta POST HTTP all'app del mittente.

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

Quindi, controlla che l'app del destinatario abbia registrato il messaggio che hai inviato.

INFO: Message arrived! Payload: Hello world!

Elimina l'abbonamento e l'argomento creati nell'ambito di questo esercizio.

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

Hai configurato due app Spring Boot che utilizzano gli adattatori Spring Integration Channel per Google Cloud Pub/Sub. Scambiano messaggi tra loro senza mai interagire con l'API Google Cloud Pub/Sub.

Hai imparato a usare gli adattatori Spring Integration Channel per Google Cloud Pub/Sub.

Scopri di più

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.