Ir al contenido principal

AOP con Spring Boot Programación orientada a aspectos ASPECTJ (en 10 minutos)


Código fuente del articulo:
https://www.dropbox.com/s/zf7vkaiy9rmmuw5/TestSpringBoot.zip?dl=0

Un paradigma no tan nuevo en la programación es la Programación Orientada a Aspectos, digamos que es ir un paso adelante de la Programación Orientada a Objetos y que ante todo es algo muy simple y que esta aquí para hacer las cosas mas modulares y ante todo simples e eficientes.

Para entender que es la AOP, primero tienes que tener claro que es un aspecto, los aspectos son todos los (cross cutting concerns) es decir todos los problemas transversales, cosas como la seguridad, los logs, las transacciones, auditoria ... etc. 

Todos estos problemas son asuntos que le conciernen a toda la aplicación y que como tal necesitan una solución global que no afecte la implementación de otros módulos. Imagina que para la aplicación REST que creamos en  este articulo (https://programmingbabel.blogspot.com/2017/09/rest-sevices-con-spring-boot-en-minutos.html ) ANTES DE CONTINUAR VE Y SIGUE LAS INSTRUCCIONES DE ESTE ARTICULO, PARA QUE TENGAS UN AMBIENTE DE DESARROLLO Y UN PROYECTO SOBRE EL CUAL TRABAJAR.   tienes que crear una validación de seguridad que impida que usuarios no registrados puedan realizar las operaciones de PUT, GET, POST, DELETE. En un modelo tradicional de programación orientada a Objetos, por lo general tendrías que implementar la validación de seguridad en cada uno de los métodos, o crear una super clase que implemente la validación y agregarla en la herencia de todas las clases donde quieras hacer la validación de seguridad y si la seguridad cambia tendrías que ir a cada método o a cada sub-implementación y modificar el código, generando controles de versión de los módulos y todo lo que implica para un proyecto este tipo de modificaciones.

Para este tipo de problemas se creo la AOP, en la programación orientada a aspectos lo que se hará sera crear una clase(nada raro hasta tes punto) con un método que se encargue de hacer la validación de seguridad y se la aplicara a todos los métodos que se filtren, que se vera algo así

@Around("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
public Object alrededor(ProceedingJoinPoint proceeding) throws Throwable{

if((Integer)proceeding.getArgs()[0]>1){
return proceeding.proceed();
}
return null;


De este código lo que tienes que notar son tres cosas (y con estas tres cosas ya habrás aprendido AOP). La primera es la anotación @Around esta anotación y todas las que encabezan los métodos en las clases que implementan los aspectos dicen cuando se va a ejecutar la intercepción, es decir si antes de ejecutar el método, después de ejecutar el método o durante la ejecución del método. los mas usados son 
@Before
@After
@Around
@AfterReturning

Lo segundo que tienes que notar es esta expresión;
 ("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
este es el filtro que utilizaremos para interceptar los llamados, es decir nuestro método se ejecutara cuando se llame a cualquier método de la clase ServicioPersonas:
com.virtuallabs.spring.ServicioPersonas.*
cualquier método que regrese cualquier valor, a eso se refiere el primer *
*
y que reciba cualquier cantidad de argumentos
(..)

Lo tercero que tienes que notar es este argumento que recibe la función
ProceedingJoinPoint proceeding


Como vamos a realizar una intercepción de alguna forma debemos poder atrapar los argumentos que recibe la función, los objetos de la clase JoinPoint permiten obtener los métodos de la función interceptada, también el objeto que contiene la función y en algunos casos decidir si la función debe ser ejecutada. los mas usados son JoinPoint y ProceedingJoinPoint. En nuestro caso usaremos ProceedingJoinPoint porque nos permite obtener el siguiente punto de corte y continuar con la ejecución. piensa en que si usas AOP puede que tengas varios aspectos implementados para una misma clase como seguridad y auditoria si un llamado tiene éxito al pasar el filtro de seguridad se debe propagar al siguiente filtro que seria el de auditoria    

Listo ya tienes una definición del método que se va a encargar de manejar el aspecto de la seguridad en tu aplicación, ahora tienes que decirle a Spring que la clase que contiene el metodo es un aspecto, esto lo haces primero agregando al pom.xml la siguiente dependencia .

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

y agregando a la clase que implementa el aspecto las siguientes anotaciones

@Aspect
@Component  

Si estas perdid@ en este punto es porque no has leído el articulo que te dije arriba (https://programmingbabel.blogspot.com/2017/09/rest-sevices-con-spring-boot-en-minutos.html)

al final tendrás una clase que se vera así:

package com.virtuallabs.spring.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ServiceMonitor {

@Around("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
public Object alrededor(ProceedingJoinPoint proceeding) throws Throwable{

if((Integer)proceeding.getArgs()[0]>1){
return proceeding.proceed();
}
return null;
}

}

Una precaución que debes tener cuando uses SpringBoot es que cualquier clase anotada como servicio o como aspecto o que realice acciones como inyección debe estar en el mismo paquete o en un subpaquete de la clase que esta anotada como @SpringBootApplication de otra forma spring no va a saber que debe leer la anotación y registrar el servicio.    

bueno nuestra implementación hace uso de proceeding.getArgs() para obtener lo argumentos del llamado a la función, el primer argumento es un Entero hace una transformación y valida que tenga valor mayor a 1, si el valor es mayor a 1 propaga el llamado al siguiente punto de intercepción que en este caso seria el método en si mismo pero si no cumple con la condición regresa un valor nulo que corta el flujo.

Ahora bien algo que debes determinar en estos llamados es en que momento haces la intercepción según las anotaciones que liste mas arriba.

Ya que el método puede tener la misma implementación y ser marcado con cualquiera de las anotaciones. pj

 @Bofore("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
public Object alrededor(ProceedingJoinPoint proceeding) throws Throwable{

if((Integer)proceeding.getArgs()[0]>1){
return proceeding.proceed();
}
return null;
}

@After("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
public Object alrededor(ProceedingJoinPoint proceeding) throws Throwable{

if((Integer)proceeding.getArgs()[0]>1){
return proceeding.proceed();
}
return null;
}

@AfterReturning("execution(* com.virtuallabs.spring.ServicioPersonas.*(..))")
public Object alrededor(ProceedingJoinPoint proceeding) throws Throwable{

if((Integer)proceeding.getArgs()[0]>1){
return proceeding.proceed();
}
return null;
}

Como puedes ver AOP no es una ciencia de otro planeta y como todo solo sirve dependiendo de la implementación que hagas.




Comentarios

Publicar un comentario

Entradas populares de este blog

Conectarse al LDAP (directorio activo) utilizando JAVA

Un LDAP es un sistema de autenticación estándar utilizado por muchas compañías para controlar el acceso a aplicaciones y recursos. Por lo general se espera que cualquier nueva aplicación haga uso del LDAP para realizar la autenticación y controlar los permisos en forma unificada, la seguridad es transversal a todos los procesos que realiza una organización. Una vez regado el cuento a lo que vinimos, como conectarse a un LDAP. Lo primero que debes saber es que no se requieren librerías adicionales, JAVA en su distribución estandar ya cuenta con todo lo que necesitas. primero tres siglas que tienes que tener en cuanta. CN  = Common Name OU  = Organizational Unit DC  = Domain Component Para conectarse primero necesitas es instanciar un Objeto de la clase LdapContext, este se encargara de manejar la conexión al LDAP y las peticiones que se hagan al mismo. por consiguiente necesitara que le entregues una serie de propiedades de conexión. Esto lo haras con un Map de la siguiente

Clases anónimas JAVA (Anonymous Classes)

Código fuente articulo: https://www.dropbox.com/s/pzw44ot0ji2metl/Lambda.zip?dl=0 Las Clases anónimas en JAVA son una solución rápida para implementar una clase que se va utilizar una vez y de forma inmediata. Por ejemplo el  EventHandler  para un botón se puede implementar en la misma asignación valiendonos de la interfaz  EventHandler  que ya esta definida. Pero mejor vamos con un ejemplo mas simple. De la definición anterior concluimos dos cosas la primera es que para crear una clase anónima es necesario haber definido una interfaz, una clase o una clase abstracta. La clase anónima lo que hará sera implementar la interfaz definida o sobre escribir los métodos definidos. Para ilustrar esto utilizaremos el ejemplo del JAVA Tutorial https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html . en este ejemplo tenemos que implementar clases que cumpliendo con la interfaz Saludo sean capaces de saludar en diferentes idiomas. El paso uno sera definir la int

Paralelismo en JAVA Executors (ExecutorService, Callables y Futures).

Código fuente articulo: https://www.dropbox.com/s/jci67120hmd0uce/Paralelismo.zip?dl=0 Para manejo de concurrencia Java desde la versión 5 presento el Concurrency API  este presento una mejora substancial en el manejo de hilos y procesos en paralelo, antes solo contabas con Thread y Runnable. lo que te obligaba a controlar la creación y el numero de hilos de ejecución, no te entregaba un resultado del procesamiento y no te dejaba controlar las Excepciones que lanzara un hilo...un hilo se lanzaba y amenos que le enviaras un un CallBack perdías todo contacto con el. Para solucionar este problema se crearon dos tipos de objetos Callables y Futures. estos dos te permiten encapsular una tarea asignándole un tipo de Objeto que sera el valor de retorno y hacer seguimiento a las tareas que ejecuto en paralelo pudiendo preguntar si ya termino, que resultado lanzo y que excepciones ocurrieron. Arranquemos con la implementación de Callable, Callable es una interfaz que te permite defini