Dopo aver analizzato i concetti teorici del pattern CQRS, si passa alla pratica con il "framework Axon", implementazione Java di CQRS. Gli articoli precedenti della serie sono consigliati come prerequisito per una comprensione completa.

La versione di riferimento è Axon 1.4 (stabile al momento della stesura), scaricabile gratuitamente dal sito ufficiale con licenza Apache 2.0.

Architettura di Axon

Axon è un framework leggero progettato per facilitare l'applicazione del pattern CQRS alle web application, risolvendo problemi di scalabilità, prestazioni, complessità e concorrenza.

Gli autori (Allard Buijze e Jettro Coenradie) hanno mirato a fornire "implementazione di tutti i building blocks di CQRS, in modo da facilitare il lavoro agli analisti e agli sviluppatori" che possono così concentrarsi sulla business logic. Nonostante sia lightweight, Axon permette interventi sullo strato CQRS quando necessario e consente l'utilizzo di altri framework (Spring, Hibernate, iBatis, etc.).

L'architettura di una web application basata su CQRS vede componenti dell'interfaccia utente che interagiscono in due modi: inviano commands tramite command handler e richiedono informazioni tramite un thin data layer.

I blocchi logici di Axon

Axon si articola in quattro macro blocchi:

1. Command Handling 2. Domain Modeling 3. Repositories and Event Stores 4. Event Processing

Il thin data layer tra UI e data source restituisce principalmente Data Transfer Object (DTO) con risultati specifici per le view. Axon non fornisce building block per questa parte poiché non differisce dalle web application classiche.

Command Handling

I command sono oggetti che contengono tutti i dati necessari per l'esecuzione. Il nome della classe esprime l'azione da compiere; i campi forniscono le informazioni necessarie.

Il Command Bus riceve i comandi e li indirizza ai Command Handler, responsabili dell'esecuzione della business logic specifica. Axon fornisce building block per implementare un'infrastruttura di command handling con caratteristiche quali validazione, logging e authorization.

Vantaggi del meccanismo esplicito

Il ricorso a un meccanismo esplicito per il dispatch dei commands comporta diversi vantaggi:

  • Tracciamento chiaro dell'intenzione del client
  • Conservazione dell'intenzione e dei dati associati
  • Esposizione facile via web services
  • Facilitazione del testing
  • Passaggio agevole dalla modalità sincrona a quella asincrona

Dettagli implementativi

Un command può essere implementato con qualsiasi oggetto. Il Command Handler deve implementare l'interfaccia org.axonframework.commandhandling.CommandHandler, dichiarando il metodo:

Object handle(T command, UnitOfWork unitOfWork) throws Throwable

Axon fornisce l'annotation @CommandHandler per trasformare semplici POJO in Command Handler. I metodi annotati dichiarano il command come primo parametro e opzionalmente una UnitOfWork come secondo parametro. Esiste un solo handler per ogni command type per Command Bus.

La classe AnnotationCommandHandlerAdapter trasforma classi annotate in implementazioni di CommandHandler. Gli handler vanno registrati nel CommandBus tramite il metodo subscribe() dell'adapter.

Metodi del CommandBus

Il CommandBus prevede due metodi:

void dispatch(Object command)
void dispatch(Object command, CommandCallback callback)

La callback opzionale implementa org.axonframework.commandhandling.CommandCallback con metodi:

void onSuccess(R result)
void onFailure(Throwable cause)

La callback può non essere invocata nello stesso thread che ha inviato il command. Se il thread richiedente necessita del risultato prima di continuare, si usa FutureCallback (combinazione tra java.util.concurrent.Future e CommandCallback di Axon).

Considerazioni sulla scalabilità

Attendere il risultato di un command compromette la scalabilità. La best practice privilegia "alto grado di scalabilità e di utilizzare il metodo dispatch che prevede un solo argomento". Quando l'esito è critico, si usa CommandTemplate, wrapper al CommandBus che consente operazioni "send and wait" in ambienti multi-threaded, con timeout opzionali.

Meccanismi del Command Bus

Il Command Bus inoltra command a un solo handler. Se nessun handler è disponibile, lancia NoHandlerForCommandException. Multiple registrazioni dello stesso command type sovrascrivono la precedente.

Axon fornisce SimpleCommandBus come implementazione CommandBus, con metodi subscribe() e unsubscribe() per registrazione/deregistrazione handler.

EventBus e Command Handler Interceptors

Gli EventBus abilitano azioni su tutti i command in arrivo. Gli Interceptor implementano CommandHandlerInterceptor con metodo:

Object handle(Object command, UnitOfWork unitOfWork,
            InterceptorChain interceptorChain) throws Throwable

Permettono azioni prima/dopo command processing e possono bloccarlo completamente.

Unit of Work

Il processing di un command è un'unità singola. Ogni azione tracciata nella Unit of Work viene notificata ai repository all'interno e gli eventi sono pubblicati all'Event Bus dopo il commit.

Le Unit of Work servono due scopi:

  • Fungono da interfaccia verso i repository (evitando salvataggi espliciti)
  • Sono riferimenti importanti per interceptor sul comportamento degli handler

Le eccezioni lanciate dai command handler causano rollback della Unit of Work per default. Nessun evento viene memorizzato o pubblicato. La classe SimpleCommandBus accetta un'istanza di RollbackConfiguration per indicare il comportamento in caso di eccezione.

Axon fornisce due implementazioni di RollbackConfiguration:

  • RollbackOnAllExceptionsConfiguration (default): rollback su ogni eccezione
  • RollbackOnUncheckedExceptionConfiguration: commit su checked exception

Conclusioni

L'articolo introduce l'architettura di Axon e il macro blocco del Command Handling. Negli articoli successivi sono analizzati i restanti blocchi e un'applicazione reale CQRS-based.

Riferimenti

  • [Sito ufficiale Axon framework](http://www.axonframework.org/)
  • Guglielmo Iozzia, "Command Query Responsibility Segregation pattern I parte: Breve panoramica su CQRS", Mokabyte 177, Ottobre 2012
  • Guglielmo Iozzia, "Command Query Responsibility Segregation pattern II parte: Quando utilizzarlo?", Mokabyte 178, Novembre 2012
  • [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html)