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 sistemi esterni.

In questo esercizio creeremo due app che comunicano utilizzando gli adattatori del canale Spring Integration forniti da Spring Cloud GCP. Questi adattatori fanno sì che Spring Integration utilizzi 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 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 e basta Leggilo e completa gli esercizi

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

Principiante Intermedio Avanzato

Come valuti la tua esperienza di utilizzo dei servizi Google Cloud Platform?

Principiante Intermedio Avanzato

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 ancora un account Gmail o Google Workspace, devi crearne uno.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.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 sempre aggiornarlo.
  • 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, di solito non ti interessa di cosa si tratta. 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 crearne uno e vedere 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 questi valori nella documentazione.
  1. Successivamente, devi abilitare la fatturazione in Cloud Console per utilizzare le risorse/API Cloud. Completare questo codelab non costa molto, se non nulla. Per arrestare le risorse ed evitare addebiti oltre a quelli previsti in questo tutorial, puoi eliminare le risorse che hai creato o il progetto. I nuovi utenti di Google Cloud possono usufruire del programma 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 è stata visualizzata 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 è caricata con 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. Gran parte del lavoro per questo codelab, se non tutto, può essere svolto 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. 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 Nuova sottoscrizione.

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 messaggi su un canale. Una volta che un messaggio si trova nel canale, viene prelevato 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 su un canale, possiamo utilizzare un gateway di messaggistica Spring Integration. Utilizzando un editor di testo di 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 a finire questi messaggi una volta inviati al 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, chiamiamo 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 in posizione, ora possiamo collegare automaticamente un oggetto PubsubOutboundGateway e utilizzarlo per scrivere un messaggio a 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 ascolta le richieste POST HTTP, 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 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 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 e li elabora.

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

9799bee5fea95aa6.png

Quindi, nella nuova sessione di Cloud Shell, cambia directory con quella dell'app ricevitore:

$ cd spring-integration-receiver

Nell'app precedente, la dichiarazione del gateway di messaggistica creava il canale in uscita per noi. Poiché non utilizziamo un gateway di messaggistica per ricevere i messaggi, dobbiamo dichiarare il nostro MessageChannel in cui arriveranno 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();
  }
}

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 e rimane in ascolto di nuovi messaggi dalla sottoscrizione exampleSubscription di Google Cloud Pub/Sub.

Abbiamo un canale in cui vengono pubblicati i messaggi in arrivo, ma cosa farne?

Elaboriamoli con un @ServiceActivator che viene attivato quando arrivano nuovi messaggi all'indirizzo 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 ricevitore.

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

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

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

Dopodiché, verifica che l'app del destinatario abbia registrato il messaggio che hai inviato.

INFO: Message arrived! Payload: Hello world!

7. Esegui la pulizia

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

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

8. Riepilogo

Configuri due app Spring Boot che utilizzano gli adattatori del 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 del 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.