Translate

Mostrando las entradas con la etiqueta AOP. Mostrar todas las entradas
Mostrando las entradas con la etiqueta AOP. Mostrar todas las entradas

miércoles, 5 de marzo de 2025

Cómo Spring Implementa AOP


Spring AOP se basa en el Patrón Proxy y la generación dinámica de clases para aplicar aspectos sin modificar el código fuente original.

Spring AOP crea proxies para interceptar llamadas a métodos y aplicar lógica adicional. Dependiendo de la estructura de la clase objetivo, Spring elige entre dos enfoques:

JDK Dynamic Proxies: Si la clase implementa una interfaz, Spring usa java.lang.reflect.Proxy para generar un proxy en tiempo de ejecución.

CGLIB (Code Generation Library): Si la clase no implementa interfaces, se genera una subclase dinámica con CGLIB.


Veamos un ejemplo de un proxy con JDK:


import java.lang.reflect.*;


interface Servicio {

    void ejecutar();

}


class ServicioImpl implements Servicio {

    public void ejecutar() {

        System.out.println("Ejecutando servicio...");

    }

}


class ProxyHandler implements InvocationHandler {

    private final Object target;

    public ProxyHandler(Object target) {

        this.target = target;

    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("[AOP] Antes de ejecutar");

        Object result = method.invoke(target, args);

        System.out.println("[AOP] Después de ejecutar");

        return result;

    }

}


public class Main {

    public static void main(String[] args) {

        Servicio servicio = (Servicio) Proxy.newProxyInstance(

            Servicio.class.getClassLoader(),

            new Class[]{Servicio.class},

            new ProxyHandler(new ServicioImpl()));

        servicio.ejecutar();

    }

}


Si la clase no implementa interfaces, Spring usa CGLIB para generar una subclase dinámica.


import net.sf.cglib.proxy.*;


class Servicio {

    public void ejecutar() {

        System.out.println("Ejecutando servicio...");

    }

}


class Interceptor implements MethodInterceptor {

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("[AOP] Antes de ejecutar");

        Object result = proxy.invokeSuper(obj, args);

        System.out.println("[AOP] Después de ejecutar");

        return result;

    }

}


public class Main {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Servicio.class);

        enhancer.setCallback(new Interceptor());

        Servicio proxy = (Servicio) enhancer.create();

        proxy.ejecutar();

    }

}


Spring AOP aplica aspectos mediante proxies dinámicos. Si la clase tiene una interfaz, usa JDK Dynamic Proxies; si no, usa CGLIB para generar una subclase dinámica. Esto permite agregar lógica sin modificar el código fuente ni el bytecode.



sábado, 1 de marzo de 2025

Programación Orientada a Aspectos (AOP) en Spring


La Programación Orientada a Aspectos (AOP, Aspect-Oriented Programming) es un paradigma que permite separar las preocupaciones transversales del código principal, como logging, seguridad, manejo de transacciones y monitoreo. Spring proporciona Spring AOP y compatibilidad con AspectJ para implementar esta funcionalidad de manera eficiente.

En una aplicación, hay funcionalidades que se repiten en diferentes partes del código (logging, manejo de excepciones, validaciones). Sin AOP, estas funciones deben implementarse de forma manual en cada clase, lo que genera código repetitivo y difícil de mantener.

AOP permite interceptar la ejecución de métodos y agregar lógica adicional sin modificar la implementación original.

Veamos un ejemplo. Para implementar un aspecto en Spring, necesitamos habilitar AOP y definir un aspecto con consejos (`advice`).

Primero agregamos la dependencia, en este ejemplo uso maven: 


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>


@Configuration

@EnableAspectJAutoProxy

@ComponentScan("com.example")

public class AppConfig {

}


Ahora definimos el aspecto de Logging


import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class LoggingAspect {

    

    @Before("execution(* com.example.service.*.*(..))")

    public void logBeforeMethod() {

        System.out.println("[LOG] - Método invocado...");

    }

}


@Aspect: Indica que la clase es un aspecto.

@Before("execution(* com.example.service.*.*(..))"): Aplica el aspecto antes de ejecutar cualquier método dentro del paquete `com.example.service`.

execution(* com.example.service.*.*(..)): Todos los métodos de cualquier clase en com.example.service.

Podemos usar @Around para envolver la ejecución de un método y medir su tiempo de respuesta.


import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;


@Aspect

@Component

public class PerformanceAspect {

    

    @Around("execution(* com.example.service.*.*(..))")

    public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed(); // Llama al método original

        long end = System.currentTimeMillis();

        System.out.println("Tiempo de ejecución: " + (end - start) + "ms");

        return result;

    }

}

@Around: Permite modificar la ejecución del método original.

joinPoint.proceed(): Ejecuta el método interceptado.

System.currentTimeMillis(): Mide el tiempo antes y después de la ejecución.


Ahora veamos un ejemplo con AspectJ: Spring AOP solo funciona con beans de Spring, pero si queremos interceptar cualquier clase, podemos usar AspectJ full.

Agregamos a nuestro pom: 


<dependency>

    <groupId>org.aspectj</groupId>

    <artifactId>aspectjweaver</artifactId>

    <version>1.9.7</version>

</dependency>


Habilitamos AspectJ en Spring Boot


@EnableAspectJAutoProxy(proxyTargetClass = true)


Definimos un aspecto con AspectJ


@Aspect

public class SecurityAspect {

    

    @Before("execution(* *(..))") // Aplica a cualquier método

    public void checkSecurity() {

        System.out.println("[SECURITY] - Verificando permisos...");

    }

}

Spring AOP permite separar lógica transversal, reduciendo la repetición de código y mejorando la mantenibilidad. Con @Aspect y @Pointcut, podemos interceptar métodos y agregar funcionalidades como logging, seguridad y performance. Para casos avanzados, AspectJ permite interceptar cualquier clase en la aplicación.