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.
liblalio_fu Stuart Coo https://wakelet.com/wake/BTMOfHQLBS34WVgc7QOzG
ResponderEliminarsaihydfeme