Introducción a Axon Framework - Parte 1





Investigando sobre arquitecturas CQRS encontre el Axon Framework.  Te comparto mis apuntes en mi camino a aprender este framework.


¿Que es CQRS?


CQRS es una forma de crear sistemas de software que hace hincapié en separar la parte  que cambia el estado de la aplicación y la parte que consulta el estado de la aplicación. 


¿Que es el Framework Axon?

Es un framework para implementar CQRS en Java. Se describe asi mismo como un framework que te permite construir aplicaciones escalables, extensibles y mantenibles; permitiendo a los desarrolladores aplicar el patrón arquitectónico Command Query Responsibility Segregation (CQRS). El cual nos da ciertos bloques importantes con sus implementaciones respectivas para crear estos sistemas como: agregados, repositorios y bus de eventos (el mecanismo de envío para eventos).  Estos últimos términos provienen del Domain Driven Design (DDD). 

En palabras simples: CQRS es escribir y leer en forma separada. 

En búsqueda de tener bajo acoplamiento, el trabajo basado en componentes, colaboración y comunicación por medio de mensajes es hoy por hoy una de las formas mas populares de conseguir CQRS. 

Una aplicación CQRS en general usa los siguientes componentes: UI, Bus de Comandos, Manejador de Comandos, Repositorios, Objetos de Dominio, Bus de Eventos, Manejador de Eventos, y todo ello conectado por medio de comandos y eventos. 


Los componentes de arriba cambian el estado de la aplicación (aquí ira la lógica de nuestra aplicación) y los componentes de abajo consulta el estado de la aplicación. 

Los usuarios usan los componentes de UI que intentarán cambiar el estado (reservar un ticket de avión, editar el profile de tu cuenta, modificar un carrito de compra, etc). Esa intención es modelada con Comandos. Esos comandos son pasados al Bus de Comandos que buscará el Manejador de Comandos necesario para poder atender el comando iniciado por el usuario. 

El cambio de estado es manejado dentro del Manejador de Comando, el cual, usa el Repositorio para cargar los objetos del Domino y ejecutar la lógica de negocio, aplicando de esta manera los cambios de estado respectivos. 

Una vez que hay cambio de estado se produce un Evento, el cual es publicado en el Bus de Eventos
Este Bus de Eventos se asegura que los Manejadores de Eventos necesarios son notificados. Estos manejadores de eventos modifican la representación de el estado de la aplicación, el cual luego el UI puede consultar. También es posible, que como respuesta a un evento, algunos nuevos comandos sean iniciados. 

¿Dónde entra el Event Sourcing?

La idea detrás de esto, es que en lugar de guardar el estado actual de la aplicación, nosotros guardamos los eventos que modifican la aplicación. 

Event Sourcing puede facilmente ser usado en un sistema CQRS, pero, esto no implica que un sistema CQRS debá usar event sourcing.  El Axon framework facilita el uso de event sourcing. 


Ejemplo: Banco

Vamos a simular el funcionamiento de un Banco, en donde vamos a implementar estas operaciones:
  • Create (crear cuenta bancaria)
    • AccountCreated
  • WithDrawMoney  (retiro)
    • MoneyWithdrawn
    • AccountOverdrawn (Exception)
  • DepositMoney (deposito)
    • MoneyDeposited
El código fuente estará en el siguiente link de github. 

Creamos nuestro ejemplo con start.spring.io:



Lo abrimos con el Intellij IDEA y tendremos esta primera versión:


Pasamos a agregar las dependencias de Axon Framework 3.3.x:


Creamos el Core API usando Kotlin:


Para que Kotlin funcione bien agregamos sus dependencias y el plugin para trabajar con Kotlin:






Vamos a crear un Agregado llamado Account, pero, primero haremos su Test Case:


Se nos pide confirmar el test y los métodos que deseamos nos genere:



La implementación del primer test es sobre como crear una cuenta de banco:




Si ejecutamos la prueba obtenemos el siguiente error:

org.axonframework.commandhandling.NoHandlerForCommandException: No handler was subscribed to command [pe.joedayz.sample.axonbank.coreapi.CreateAccountCommand]


Esto es natural porque el Agregado Account no ha sido implementado y como dice el mensaje no hay manejador para el comando CreateAccountCommando. 

Implementamos el Agregado Account:


Ejecutamos el test y obtenemos exito:


Ahora vamos a implementar el caso de prueba para retiro:


Si ejecutamos obtenemos el error:

java.lang.IllegalArgumentException: Invalid command. It does not identify the target aggregate. Make sure at least one of the fields or methods in the [WithdrawMoneyCommand] class contains the @TargetAggregateIdentifier annotation and that it returns a non-null value.

Para ello modificamos la clase Kotlin para que dicho Comando tenga esa anotación:


Desarrollamos un nuevo test para probar un retiro con una cantidad absurda:



Dicho test podrá ejecutarse implementando el Agregado Account:


y la clase OverdraftLimitExceededException extends Exception. 

Ejecutamos el Test y obtenemos el exito esperado:



Desarrollamos un nuevo test que prueba dos retiros simultaneos, pero, donde el balance es incorrecto:



Ejecutamos el Test y obtenemos el exito esperado:



Application

Creamos una clase adicional Application para configurar nuestro Agregado Account, un almacen de eventos en memoria y ejecutamos algunos comandos para ver si funciona la lógica de overflow.


Efectivamente al ejecutar este código obtenemos OverdraftLimitExceededException.


Ahora pasaremos a configurar un Bus de Comandos asincrono:



El cual como vemos en el log crea hilos para ejecutar los comandos.


Eso fue para probar. Ahora configuraremos Axon en el proyecto Spring Boot:



Con esto logramos un bus de comandos, un bus de eventos auto configurado para nuestro proyecto. Por ahora es suficiente.

Pasamos a crear un Event Store:



Dicha anotación @EnableAxon también hace un scan por Agregados. Por esta razón usaremos la anotación @Aggregate para decorar nuestro agregado.


Si ejecutamos la aplicación en este punto no pasará nada.  Por eso vamos a configurar el CommandBus y a hacer la misma prueba que hicimos en la clase anterior.



Obtenemos el mismo resultado: pe.joedayz.sample.axonbank.account.OverdraftLimitExceededException: null

Si observamos el log todo se hace en el hilo principal, debido a ello, vamos a configurar un CommandBus asincrono.



Al ejecutar encontramos una exception: No encuentra nuestro agregado.



Y eso es por el orden de creación del comando, como ahora es asincrono, falla si no encuentra el agregado. Para evitar eso, hacemos el siguiente cambio:



Y al ejecutar todo en orden:


Nosotros podemos hacer más personalización como el definir un repository para nuestro Agregado Account.




Pero también hay que crear un bean para transacciones y por ahora no usaremos el command bus.


Volvemos a ejecutar y el resultado es:


Listo eso es todo por ahora.

Enjoy!

Joe



Share:

Monitoring your micro services with Spring Boot Admin

This new joetip is for those who have in their architecture some micro-services developed with Spring Boot and are already using some Spring Cloud projects such as Spring Cloud Config and Spring Cloud Eureka as Discovery server.

The Spring Boot Admin is a project developed by CodeCentric which is available for free at https://github.com/codecentric/spring-boot-admin so we can monitor our microservices.

In order for these micro-services to be monitored, we have 2 options:


  1. Placing the dependency of spring boot admin client on each project
  2. Or configuring the Eureka (Consul or Zookeeper) so that you can monitor the micro-services that are already registered in it.


I will explain step by step what has to be done to work with the spring boot admin in our microservices cluster. But, if you are impatient and already want to try it, here is the GitHub repository: https://github.com/joedayz/spring-boot-admin-cloud-finchley.

For my demos I will use the following projects and the following versions:


  1. Spring Boot 2.0.1.RELEASE
  2. Spring Cloud Finchley.RC1
  3. Spring Boot Admin 2.0.2

Spring Cloud Config

In a micro-services architecture, it is very common for the configuration to be decentralized from themselves.
That is, instead of having the configuration to BD, SMTP, JPA, Security in your micro-service along with the source code or in other words in the same JAR, this is in an external GIT repository from where your micro services owe it. Get on startup (startup) so they can run without problems.

In summary:





The Spring Cloud Config is a Spring Cloud project that fulfills this function of providing configuration to microservices via HTTP.

Create a Spring Config Server

To create a configuration server we will create a spring boot project from scratch with https://start.spring.io/ with the following dependencies.




With this setup, we will have what it takes to start a Spring Cloud Config server. The next step is to configure the spring boot and spring cloud versions that I described when starting the article.





You can see the complete code in the pom.xml of the config-server.
Then in the Application class, we enable the configuration server role with the annotation @EnableConfigServer.



Finally, we will configure the access to the GIT repository from which we will obtain the parameters. The application.yml path that will be available for my micro-services will be in this link https://github.com/joedayz/spring-boot-admin-cloud-finchley/blob/master/ConfigData/application.yml.

Let's see the configuration:



We execute the project and see if it exposes the data in JSON format for any micro-service that requests it.

http://localhost:8001/application/default

The output is as follows:


If you have reached this point, congratulations, you already know how to create a Spring Cloud Config Server.

Spring Cloud Eureka

n a microservices architecture with Spring Cloud we have the Service Discovery Server (Discovery Server) which has the registry of all the micro-services of your architecture. The is that he knows in what server, port, number of instances of the same, current state (UP or DOWN) is the microservice. There are several in the market, but, we are going to use the Eureka.

The micro-services, in general, register themselves in the Eureka. We'll talk about that later.


Crear un Spring Cloud Eureka

To create a Eureka server we will use https://start.spring.io/ to create a Spring Boot project with the following configuration:



With this setup, we will have what it takes to start a Spring Cloud Eureka server. The next step is to configure the spring boot and spring cloud versions that I described when starting the article.


You can see the complete code in the pom.xml of the config-server.

To convert this project into a Eureka server we use this annotation @EnableEurekaServer.


Then, we will configure the server with basic authentication so that they can enter it using as user: eureka and password: password.


The file can be seen in this link.

We execute the project and then go to http://localhost:8010, after entering the user (eureka) and password (password) we will obtain this result.



NOTE: Here you will see the registered microservices. Here the recommendation is to have several Eureka to have high availability, because of falling the Eureka, your architecture becomes inconsistent. In this article for didactic reasons, we are only running a single eureka.

If you got to this point, congratulations, you know how to create and execute a Spring Cloud Eureka, the Discovery Server of your architecture.

Example with an architecture of Micro Services

A micro-services architecture generally uses a gateway as a facade or entrance to your micro-services cluster. And it is through the gateway that we access the micro-services.



For didactic reasons, we will make a simple solution. The gateway will show a sentence that is the result of invoking micro-services subject + verb + article + adjective + noun.


The result should be something like this:



Explained the example of @kennyk65 that in the end we will monitor with Spring Boot Admin, we will explain how to create the microservices and the gateway, which will use the spring cloud config to get their configurations and start correctly, as well as register them same in the Eureka (later we will see why this is important).

Micro Servicio

Requirements: Before creating and running the micro-services, make sure you have the Spring Cloud Config and Eureka running.

To create the microservices: subject (it will return subjects), verb (it will return verbs), article (it will return articles), adjective (it will return adjectives) and noun (it will return substantives) we use the page https://start.spring.io/ with the following dependencies:




We modified the file pom.xml with the versions of spring boot and spring cloud that we described at the beginning of the article.


From there, we configure the Spring Boot project so that it registers in the Discovery Server Eureka with the annotation @EnableDiscoveryClient.





The Class to model each word is as follows:

package demo;

/**
 * 'Word' object is nicely represented in JSON over a regular String.
 */
public class Word {

 public String word;

 public Word() {
  super();
 } 
 
 public Word(String word) {
  this();
  this.word = word;
 }

 public String getWord() {
  return word;
 }

 public void setWord(String word) {
  this.word = word;
 }
 
 
}



The Micro Service when invoked via REST will return a word depending on the active profile (subject, verb, article, adjective, noun). For this, you will have to obtain a series of words or alternatives that will be assigned to the String words from the Spring Cloud Config with @Value ("$ {words}").




But, as all that is achieved, then, with the configuration that we will find in application.yml and bootstrap.yml of the project.

application.yml

It is necessary to have the reference to words so that the application does not fail. Remember that it will be the spring cloud config that will give us the real list of words according to the profile that is active.


bootstrap.yml

This is the key configuration, which will allow us to work with the Spring Cloud Config (the URI) to obtain the words, with which service ID will be registered in Eureka and the name of the microservice and available profiles with which we can execute it.


The above described can be observed in the following configuration:



To be able to execute the micro-services with different profiles. You have the following shell to run the micro-service as subject, verb, article, adjective, and noun.


If we review the Eureka we will see all the micro-services started.



If you arrived at this point you already have 5 micro-services running and getting your configuration from the Spring Cloud Config and registered in the Eureka. Congratulations.

Gateway

The requirement for this part: The microservices words in their different profiles must be running.

It is not good practice to allow the outside world to access your microservices directly, there are no exceptions, even if they are APIs that are going to expose data out of your system. For this, the best practice is to have a Gateway. To have one there is a project called Spring Cloud Zuul which we will use in this demo that will give us the services of router and filter.

To create it also go to https://start.spring.io/ and create a Spring Boot project with this unit.



The  pom.xml After making the version changes, it remains that way.

We converted this project with Spring Boot in Gateway with the annotation @EnableZuulProxy.


In the project, we will go to a view where we will call the micro-services. For that, a simple @Controller is enough.


In the sentence.html view with thymeleaf we will use jquery to make calls to services in this way:


And with Jquery call the service and place the result in the respective span.



For all this to work, the magic is again in the application.yml where we indicate whether we want to allow thymeleaf to cache or not, as well as the prefix to use when we want to call the microservices /services/verb for example.


and in the bootstrap.yml we put the name of the micro-gateway service and its association with the Spring Cloud Config.


We start the Gateway and the result should be:





If you got to this point congratulations, you know how to create a gateway.

Spring Boot Admin


And the moment arrived. At this point you will say, and where is the spring boot admin ?, return my money.


After accommodating the versions and dependencies the pom.xml remains as in previous sections.


In the same way, to convert this project spring boot into spring boot admin, we use the annotation @EnableAdminServer.


To provide some security (basic HTTP authentication) we will use the credentials: admin as user and password as the password.


Finally, in the application.yml, we do the magic: Port where it will run, the name of the application, basic HTTP security and its connection to the Eureka.


We execute the project:


(Login)


(List of microservices)


(Panel of microservices)



(complete information of the microservice)


If you got to this point. Congratulations, you know how to run a spring boot admin.

Enjoy!



Joe










Share: