Programación orientada aspectos(AOP)

La programación orientada aspectos (AOP) es un paradigma de programación que complementa la programación orientada a objetos (POO), AOP permite modular conceptos que son trasversales a la aplicación y que con POO son difíciles de encapsular en objetos o funciones. Entiéndase por transversal a conceptos o funcionalidades que están distribuidas por gran parte de la aplicación.

Puede estar tentado a utilizar POO para la implementación de funcionalidades transversales, esto llevara a repetir varias líneas de código en los componentes donde desea implementar la funcionalidad, con las consecuentes dificultades de mantenimiento y desarrollo que ello implica. Más allá de aquello, es que al hacerlo se le esta asignado responsabilidades al componente(clase) que no le compete, ya que por lo general las funcionalidades transversales son propio de la aplicación. Por ejemplo, el sistema de log, el manejo de transacciones, entre otros.

En la literatura AOP a estas funcionalidades trasversales se las denomina preocupaciones transversales.

AOP con Spring

Spring provee el marco Spring AOP y además brinda soporte para el estilo @AspectJ para implementar la AOP. Vamos a centrarnos en construir aspectos con @AspectJ.

Spring utiliza el aspecto como unidad para modular las funcionalidades transversales. Un aspecto es una clase java donde se implementan las diferentes preocupaciones tranversales.

@AspectJ

Este estilo permite definir aspectos mediante clases java con anotaciones, tenga presente que @AspectJ es un marco independiente a Spring, sin embargo, este ultimo brinda un soporte completo para utilizarlo.

Podemos utilizar Spring AOP mediante XML o anotaciones, revisaremos esta última opción que es la forma más común.

Proyecto AOP Spring

Agregamos las siguientes dependencias al pom.xml

  • Agregar dependencia spring-aop
    <dependency> 	
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.15</version>
    </dependency > 
    

  • Agregar dependencia aspectjweaver
    <dependency> 	
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.8</version>
     </dependency > 
    

Clase Cliente

Para el ejemplo, defina la siguiente clase

@Component
 public class Cliente{
    public void insertar(){ 	
        System.out.println("Insertando el cliente");
    }
    //.....
}

Crear un aspecto

Definimos un clase java y agregamos la anotacion  @Aspect para definir la clase como un aspecto, además anotamos con @Component para registrar el aspecto como un bean de Spring.

  •  @Component
      @Aspect
      public class AspectCliente{
       // ---- 
    }
    

Punto de corte(Pointcut)

Los Pointcut son expresiones que indican sobre que metodos, clases o paquetes debe actuar el aspecto. Utilize la anotación @Pointcut sobre un método que este dentro de una clase anotada con @Aspect

La expresión Pointcut debe seguir la siguiente sintaxis:

El texto resaltado con rojo, es obligatorio en la expresión
    Detalles:
  • execution(expresion): permite ejecutar la expresion que se define entre ()
  • modificador (opcional): especifica un modificador de acceso (public, private, etc).
  • tipo-retorno: especifica un tipo de retorno (void, String, etc).
  • tipo-declaracion (opcional): especifica el tipo/clase de la declaración (x.y.Service, x.y.Cliente, etc).
  • nombre-metodo: especifica un método sobre el cual el aspecto actuará (loginCliente(), etc).
  • parametro : especifica parámetros de la declaración (String, int, etc), o simplemente ().
  • Ejemplo básico
    @Pointcut("execution(public void insertar())") // Expresión Pointcut
        public void  logAccion(){}  // La Firma(Signature) Pointcut 
    

    El Pointcut logAccion() actuará sobre todos los métodos que coincida con la expresión public void insertar().

  • Un @Pointcut consta de dos partes
    • Expresion Pointcut: patrón dentro @Pointcut que determina donde actuará
    • Firma Pointcut: método sobre el que se anota @Pointcut, debe ser sin retorno(void)
  • Tenga presente que los @Pointcut simplemente son definiciones  que determinan donde deberá actuar un aspecto, por ello no llevan lógica en el método de definición.

Consejos (Advice)

Los consejos o advice referencian a uno o varios @Pointcut, un advice determina el momento(antes, despues) en que debe actuar @Pointcut. Tenemos varios tipos de advice:

  • @Before: Se ejecuta antes del método
  • @AfterReturning: Se ejecuta despues de la ejecución normal del método(Sin que ocurra una excepción)
  • @AfterThrowing: Se ejecuta despúes que el método lanze una excepción
  • @After: Se ejecuta despúes del método, tanto si se ejecuta normalmente o con excepciones.
  • @Around: Se ejecuta alrededor del método, es decir tanto antes como despues.

Un advice debe definirse dentro de un clase anotada con @Aspect.

  •    @Before("logAccion()")
        public void  beforeInsert(){
          System.out.println("Antes de insertar un cliente")
        }
        
        @After("logAccion()")
        public void  afterInsert(){
          System.out.println("Despues de insertar un cliente")
        } 
        
    

    Los advice @Before y @After estan referenciando al mismo @Pointcut logAccion(), sin embargo, son llamados en momentos diferentes. El primero se ejecutará antes del punto de corte definido por logAccion(), mientras que @After se ejecutará despues de ejecutar el punto de corte.

Habilitar el soporte para @AspectJ

Debe agregar la anotación @EnableAspectJAutoProxy en el contenedor IoC para habilitar la compatibilidad con Spring para configurar Spring AOP.

  • Utilizando anotaciones
       @Configuration
       @ComponentScan(basePackages = "x.y....")
       @EnableAspectJAutoProxy
        public class  SpringConfig{...} 
    

    Recuerde que la clase anotada con @Aspect, tambien fue anotada con @Compontent, no olvide scanearla en @ComponentScan.


  • Mediante XML
       <aop:aspectj-autoproxy/>
    

    Para utilizar esta etiqueta debe agregar el name-space de aop, consulte esquema completo para aop para obtener.

Ejecutar programa

Cree un bean de la clase Cliente e invoque al método insertar(), deberá ver la siguiente salida en consola

 System.out.println("Antes de insertar un cliente") // Advice @Before
 System.out.println("Insertando el cliente");       // Ejecución del método
 System.out.println("Despues de insertar un cliente") // Advice @After

Al invocar al método insertar(), este coincide con el @Pointcut("execution(public void insertar())") del aspecto, el mismo es referenciado por los advice @Before y @After que ejecutarán la logica definida en ellos .

En entradas posteriores revisaremos más sobre este tema

¡Hasta pronto 👋👍!

Comentarios

Entradas populares de este blog

JWT (Json Web Token)

Instalar Java Developmet Kit(JDK)

Curso de Spring