Messaggistica con l'integrazione Spring e Google Cloud Pub/Sub

1. Panoramica

Spring Integration fornisce un meccanismo di messaggistica per scambiare Messages tramite MessageChannels. Utilizza gli adattatori di canale per comunicare con i sistemi esterni.

In questo esercizio, creeremo due app che comunicano utilizzando gli adattatori di canale Spring Integration forniti da Spring Cloud GCP. Questi adattatori fanno in modo che Spring Integration utilizzi Google Cloud Pub/Sub come backend di scambio di messaggi.

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

Questo tutorial utilizza il codice campione della guida introduttiva di 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
  • Un browser, ad esempio 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 nella creazione di app web HTML/CSS?

Principiante Intermedio Esperto

Come valuteresti la tua esperienza nell'utilizzo dei servizi Google Cloud?

Principiante Intermedio Esperto

2. Configurazione e requisiti

Configurazione dell'ambiente autonomo

  1. Accedi alla console Google Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai già un account Gmail o Google Workspace, devi crearne uno.

b35bf95b8bf3d5d8.pnga99b7ace416376c4.pngbd84a6d3004737c5.png

  • Il nome del progetto è il nome visualizzato per i partecipanti a questo progetto. È una stringa di caratteri non utilizzata dalle API di Google. Puoi aggiornarla in qualsiasi momento.
  • L'ID progetto è univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo l'impostazione). La console Cloud genera automaticamente una stringa univoca; in genere non ti interessa quale sia. Nella maggior parte dei codelab, dovrai fare riferimento all'ID progetto (in genere identificato come PROJECT_ID). Se non ti piace l'ID generato, puoi generarne un altro casuale. In alternativa, puoi provare a utilizzare il tuo e verificare se è disponibile. Non può essere modificato dopo questo passaggio e rimane per tutta la durata del progetto.
  • Per tua informazione, esiste un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre i valori nella documentazione.
  1. Dopodiché, dovrai abilitare la fatturazione nella console Cloud per utilizzare le risorse/API Cloud. L'esecuzione di questo codelab non costerà molto, se non nulla. Per arrestare le risorse ed evitare addebiti di fatturazione oltre questo tutorial, puoi eliminare le risorse che hai creato o eliminare il progetto. I nuovi utenti Google Cloud possono usufruire del programma di 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 Cloud Shell

  1. Nella console Cloud, fai clic su Attiva Cloud Shell 853e55310c205094.png.

55efc1aaa7a4d3ad.png

Se è la prima volta che avvii Cloud Shell, viene visualizzata una schermata intermedia che ne descrive le funzionalità. Se hai visualizzato una schermata intermedia, fai clic su Continua.

9c92662c6a846a5c.png

Bastano pochi istanti per eseguire il provisioning e connettersi a Cloud Shell.

9f0e51b578fecce5.png

Questa macchina virtuale è dotata di tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. La maggior parte, se non tutto, del lavoro in questo codelab può essere eseguita con un browser.

Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è autenticato e il progetto è impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto:
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].

3. Eseguire il provisioning delle risorse Pub/Sub

Vai alla pagina degli argomenti di Google Cloud Pub/Sub.

Fai clic su Crea argomento.

4c938409dc7169a6.png

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

e2daeec91537f672.png

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

975efa26e5054936.png

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

f7a91d9e1cb48009.png

4. Inizializzare le applicazioni Spring Boot

Dopo l'avvio di 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=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. Creare un'applicazione per inviare messaggi

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

$ cd spring-integration-sender

Vogliamo che la nostra app scriva i messaggi in un canale. Una volta che un messaggio è 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.

Affinché la nostra app possa scrivere in un canale, possiamo utilizzare un gateway di messaggistica Spring Integration. Utilizzando un editor di testo da vim, emacs o nano, dichiara un'interfaccia 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 vanno questi messaggi dopo che sono nel canale?

Abbiamo bisogno di un adattatore del canale in uscita per utilizzare i nuovi messaggi nel canale e pubblicarli in un argomento 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");
  }
}

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 del canale in uscita, PubSubMessageHandler, per pubblicare il messaggio nell'argomento exampleTopic di Google Cloud Pub/Sub.

Con l'adattatore del canale, ora possiamo collegare automaticamente un oggetto PubsubOutboundGateway e utilizzarlo per scrivere un messaggio in 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("/");
  }
}

Grazie all'annotazione @PostMapping, ora abbiamo un endpoint che è in ascolto delle richieste HTTP POST, ma non senza aggiungere anche 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 {
  ...
}

Assicurati che JAVA_HOME sia impostato sulla versione corretta.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

Esegui l'app di invio.

# 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 arriveremo più avanti.

6. Creare un'applicazione per ricevere messaggi

Abbiamo appena creato un'app che invia messaggi tramite Google Cloud Pub/Sub. Ora creeremo un'altra app che riceve questi messaggi ed elabora.

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

9799bee5fea95aa6.png

Poi, nella nuova sessione di Cloud Shell, cambia directory nella directory dell'app del ricevitore:

$ cd spring-integration-receiver

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

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

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

Questo adattatore si associa a pubsubInputChannel ed è in ascolto di nuovi messaggi dall'abbonamento exampleSubscription di Google Cloud Pub/Sub.

Abbiamo un canale in cui vengono pubblicati i messaggi in entrata, ma cosa fare con questi messaggi?

Elaboriamoli con un @ServiceActivator che viene attivato quando arrivano nuovi messaggi a pubsubInputChannel. In questo caso, registreremo solo il payload del messaggio.

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

Assicurati che JAVA_HOME sia impostato sulla versione corretta.

export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

Esegui l'app del ricevitore.

$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081"

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

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

Poi, verifica che l'app del ricevitore abbia registrato il messaggio che hai inviato.

INFO: Message arrived! Payload: Hello world!

7. Esegui la pulizia

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

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

8. Riepilogo

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

9. Complimenti!

Hai imparato a utilizzare gli adattatori di canale Spring Integration 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.