Processi Asincroni in Spring

In questo articolo vogliamo descrivere una caratteristica molto interessante del framework Spring, ovvero la capacità di gestire compiti che richiedono una lunga elaborazione mediante l’utilizzo di thread asincroni. Questa caratteristica è molto utile quando si ha la necessità di realizzare servizi in grado di scalare in base al carico, e con Spring è possibile abilitarla semplicemente attraverso l’utilizzo di due semplici annotazioni: @Async e @EnableAsync.

Abilitazione del Supporto Asincrono

Procediamo innanzitutto creando un nuovo progetto Spring boot con Maven; il pom.xml avrà il seguente aspetto:

Aggiungiamo quindi la solita classe Main annonata con @SpringBootApplication per abilitare tutte le caratteristiche di autoconfigurazione di Spring.

Infine abilitiamo il supporto al processamento asincrono definendo una classe di configurazione ed annotandola con @EnableAsync:

Questa semplice annotazione attiva la capacità di Spring di processare ogni metodo annotato con @Async in thread separati.

Definizione del Metodo Asincrono

Come anticipato affinché l’elaborazione di un metodo avvenga in un thread separato è sufficiente annotare lo stesso con @Async. Ci sono però alcune regole che devono essere tenute a mente quando si utilizza tale annotazione:

  1. Il metodo annotato deve essere pubblico, questo perché Spring utilizza una classe proxy per la sua gestione.
  2. Il punto di invocazione del metodo non deve essere all’interno della classe che lo definisce, altrimenti verrebbe bypassata la classe proxy che lo gestisce.
  3. Se il metodo deve restituire un valore questo dovrà essere di tipo CompletableFuture o Future.

Seguendo queste regole, introduciamo quindi una classe BatchService in cui definiamo il metodo batchUpdate:

Infine definiamo la classe BatchController in cui implementiamo un semplice metodo REST start per l’attivazione del batch:

Una volta avviato il progetto con la usuale istruzione maven mvn spring-boot:run sarà possibili avviare il nostro batch asincrono aprendo il browser ed inserendo nella barra degli indirizzi la URL: http://localhost:8080/batch/start. DI seguito è riportato il log generato, in cui si nota come le classi BatchController e BatchService sono eseguite su due thread differenti.

Gestione del Pool di Thread

Come è facile immaginare per la gestione dei processi in background Spring utilizza un pool di Thread. Per la sua configurazione ricercherà, tra i bean definiti nel contesto dell’applicazione, un bean di tipo TaskExecutor o un chiamato taskExecutor. Se un bean con queste caratteristiche non viene trovato, Spring instanzierà uno di quelli predefiniti (si veda qui) come ad esempio il ThreadPoolTaskExecutorSimpleAsyncTaskExecutor.

Più interessante però è vedere come sia possibile personalizzare il comportamento del pool secondo le nostre esigenze. A tale scopo abbiamo due possibili opzioni:

  1. dichiarare l’executor da utilizzare al livello di metodo (quello annotato con @Async per intenderci);
  2. definire l’executor di default a livello di applicazione.

Nel primo caso dobbiamo innanzitutto definire un beal che implementa Executor.

Quindi dobbiamo citarlo nell’annotazione @Async del metodo batchUpdate:

Se eseguiamo l’applicazione come fatto sopra, vedremo nei log che il nome del thread è ora  Method-Thread::1, concordemente a quanto definito in configurazione impostando la proprietà setThreadNamePrefix dell’Executor.

Volendo invece optare per il secondo caso, in cui vogliamo sovrascrivere Executor a livello dell’intera applicazione, è necessario implementare l’interfaccia AsyncConfigurer, la quale definisce il metodo getAsyncExecutor() che restituisce l’executor da utilizzare:

Questa volta eseguendo l’applicazione, dopo aver rimosso la dichiarazione dell’executor threadPoolTaskExecutor dall’annotazione @Async, noteremo nel log che il thread è ora chiamato App-Thread::1.

Si noti, in conclusione, che la flessibilità di Spring consente non solo di definire un executor di default ma anche di avere più executor da utilizzare in modo differente su metodi asincroni diversi.

Il Codice Sorgente

Il codice sorgente del progetto è scaricabile qui spring-async.

 

How useful was this post?

Click on a star to rate it!

Average rating 5 / 5. Vote count: 1

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!