Spring AOP y AspectJ en tres patadas

Inauguramos el nuevo nombre y aspecto del blog, que pasa de “Posteando mientras…” a “El Recetario”, con una nueva receta de Spring. En este caso vamos a cocinar algo con Spring AOP.

Qué cocinamos

Spring AOP es la parte de Spring relacionada con la porgramación orientada a aspectos. La programación orientada a aspectos es un paradigma informático que se fundamenta en programar en función de un aspecto, funcionalidad o característica concreta, en lugar de hacerlo centrado en un servicio o método específico. Es decir, que se puede codificar una funcionalidad o actividad no en función de un método o servicio específico, si no para un conjunto de ellos que representan una característica o aspecto representativo de la aplicación.

Por ejemplo, se puede programar la escritura de logs, la intercepción de excepciones, la generación de comentarios o auditorías en función de la ejecución o resultados de varios métodos que implementan una única funcionalidad o característica de la aplicación final. Así, podemos crear una entrada en un log cada vez que se invoque un método de la capa de servicios, o cada vez que se llame a un método de un paquete concreto.

Las acciones a realizar o implementación del aspecto es el “Advice”. Un aspecto puede tener varios “advices”, y cada “advice” estara asociado a un punto de interés o “pointcut”. El punto de interés que se usa para indicar cuando ha de ejecutarse el “advice”, es decir, los métodos que se quiere controlar.

AspectJ facilita la creación de los aspectos usando anotaciones.

Ingredientes

  • Spring Boot
  • Spring MVC
  • Spring AOP
  • AspectJ
  • Log4j
  • Maven

Paso a paso

1. Pom.xml

Configuramos el pom.xml de Spring Boot para que resuelva las dependencias necesarias para crear una aplicación con Spring AOP. La aplicación va a ser una simple API REST que recibirá una petición para contar cuantas veces aparece una determinada letra en una palabra, de ahi que necesitemos Spring MVC para la parte web. Se va a capturar la invocación y resultados de la ejecución de esta API usando aspectos y se escribirá en un log cuando esto ocurrá usando Log4j.

2. Inicializar Spring Boot

Se puede obtener más información acerca de Spring Boot en este otro post. Basta con incluir el siguiente código para inicializar la aplicación como Spring Boot. Esto hará que se ejecute en el Tomcat embebido que se carga automaticamente al incluir las dependencias de Spring MVC.

3. Crear el servicio que servirá de pointcut para los advices del aspecto

Como ejemplo práctico disponemos de un servicio que recibe una palabra y una letra. Éste cuenta cuantas veces aparece la letra en dicha palabra y devuelve la cuenta.

4. Controlador REST

Como se ha mencionado antes, se va ha implementar un servicio web tipo REST que se invocará desde un navegador web. Este servicio recibe en su URL una palabra y una letra, que seran los datos que se le pasarán al servicio antes creado.

5. Aspecto

Por último lo interesante de esta receta. La creación del aspecto usando las anotaciones de AspectJ. El aspecto puede tener varios “advices”, a saber:

  • @Before – Para antes de la ejecución del pointcut
  • @After – Para después de la ejecución del pointcut
  • @AfterReturning – Para después de la ejecución y recibiendo lo que se retorna
  • @AfterThrowing – Para después de que se lanza una excepción
  • @Around – Para antes y después del pointcut

Declaramos la clase como Aspect y como Component para que Spring la instancie automaticamente y la configure como aspecto:

Implementamos a modo de ejemplo los sigueintes advices:

- logBefore, para que escriba un mensaje en el log antes de ejecutar el servicio anterior:

Usamos la anotación @Before y el pointcut será la ejecución de cualquier método que tenga el texto Service en su nombre dentro del paquete net.luisalbertogh.springaop, independientemente de lo que reciban como argumento.

- logAfterReturning, para que escriba en el log después de la ejecución del servicio, e imprima el resultado obtenido:

Al igual que en el caso anterior, se usa la anotación y se define el pointcut correspondiente, pero en este caso además se añade el resultado (result).

- logAfterThrowing, para que escriba después de lanzar una excepción e indique el mensaje de error en el log:

- logAround, para que escriba en el log antes y después de la ejecución del servicio. En este caso, lo que ocurre es que se pasa la ejecución del pointcut al advice. Entonces para que continue la ejecución del servicio se usa joinPoint.proceed().

El resultado

En el navegador se vería esto:

Spring AOP

Spring AOP

Y en el log o en la consola:

INFO : net.luisalbertogh.springaop.controllers.ExampleController – Entering in CALCULATE
INFO : net.luisalbertogh.springaop.aspect.LogAspect – logBefore
INFO : net.luisalbertogh.springaop.aspect.LogAspect – Log before in: countCharsService
INFO : net.luisalbertogh.springaop.aspect.LogAspect – logAfterReturning
INFO : net.luisalbertogh.springaop.aspect.LogAspect – Log after in: countCharsService
INFO : net.luisalbertogh.springaop.aspect.LogAspect – - And value returned is: 4
INFO : net.luisalbertogh.springaop.controllers.ExampleController – Finishing CALCULATE

El proyecto completo aqui. Y también en Github.