CodeGym /Cursos /Módulo 5. Spring /Profundizando en AOP: análisis detallado de aspectos, poi...

Profundizando en AOP: análisis detallado de aspectos, pointcuts y advices

Módulo 5. Spring
Nivel 3 , Lección 1
Disponible

En la clase anterior vimos los conceptos básicos de AOP. Pero hay una gran diferencia entre "conocer los términos" y "entender cómo funciona". Vamos a mirar bajo el capó y a desentrañar los detalles.

1. Aspecto: no solo un módulo

Ya sabemos que un aspecto es un módulo para tareas cross-cutting. Pero ¿cómo Spring lo crea y lo gestiona?

Ciclo de vida del aspecto

Un aspecto en Spring no es solo una clase con la anotación @Aspect. Es un ciudadano de primera clase del contenedor Spring con su propio ciclo de vida:

  1. Inicialización: Spring crea los aspectos en la etapa más temprana de carga del contexto
  2. Proxificación: basándose en los aspectos se crean proxies para los beans objetivo
  3. Inyección: el aspecto puede usar otros beans mediante @Autowired
  4. Ejecución: Spring invoca los métodos del aspecto cuando se activan los triggers

Particularidades del funcionamiento de los aspectos

A diferencia de los beans normales, los aspectos tienen varias características importantes:

  1. Priorización: cuando varios aspectos apuntan al mismo método, el orden de ejecución es crítico:
    
    @Aspect
    @Order(1)  // Primero comprobaremos los permisos
    public class SecurityAspect { ... }
    
    @Aspect
    @Order(2)  // Luego registraremos
    public class LoggingAspect { ... }
    
  2. Autoaplicación: por defecto los aspectos no se aplican a métodos dentro de los propios aspectos — esto previene la recursión

2. Pointcut: ajuste fino de los puntos de aplicación

En la clase anterior vimos la sintaxis básica de los pointcuts. Ahora analizaremos cómo Spring los procesa y qué posibilidades avanzadas existen.

Anatomía de un pointcut

Un pointcut no es solo una cadena con wildcards. Es un lenguaje potente para describir los puntos de aplicación:


@Pointcut("execution(* com.example.service.*.*(..)) && @annotation(Secured)")
public void securedMethods() {}

Aquí sucede lo siguiente:

  • execution() — define el patrón para hacer match con métodos.
  • && — combina condiciones.
  • @annotation() — comprueba la presencia de una anotación.

Composición de pointcuts

Los pointcuts se pueden combinar para crear lógicas más complejas:


@Pointcut("inService() && secured()")
public void securedServiceMethods() {}

@Pointcut("within(com.example.service.*)")
public void inService() {}

@Pointcut("@annotation(Secured)")
public void secured() {}

A menudo se usan los siguientes patrones:

  • execution(* com.example..*(..)): Todos los métodos en todo el paquete com.example.
  • within(com.example.service.*): Métodos en clases concretas.
  • @annotation(org.springframework.transaction.annotation.Transactional): Métodos con una anotación concreta.

¿Cómo funcionan los pointcuts por debajo del capó?

Spring "escucha" las definiciones de pointcuts y las enlaza con los join points (por ejemplo, métodos) que coinciden con el patrón. Esos join points serán los lugares donde se ejecuten los aspectos.


3. Advice: mecánica de ejecución

Sabemos los tipos de advices (@Before, @After, etc.), pero ¿cómo los ejecuta Spring?

Orden de ejecución de los advices

Cuando en un método hay varios advices, se ejecutan en el siguiente orden:


@Around (inicio)
@Before
        → Método
@AfterReturning/@AfterThrowing
@After
@Around (fin)

Acceso al contexto

En los advices tienes acceso a mucha información contextual:


@Before("execution(* *(..))")
public void beforeMethod(JoinPoint jp) {
   String methodName = jp.getSignature().getName();
   Object[] args = jp.getArgs();
   Object target = jp.getTarget();
}

Ejemplo: Before


@Before("execution(* com.example.service.OrderService.placeOrder(..))")
public void logBeforePlaceOrder() {
    System.out.println("Antes de llamar al método placeOrder()");
}

Ejemplo: After


@After("execution(* com.example.service.OrderService.placeOrder(..))")
public void logAfterPlaceOrder() {
    System.out.println("Después del método placeOrder()");
}

Ejemplo: Around


@Around("execution(* com.example.service.OrderService.placeOrder(..))")
public Object logAroundPlaceOrder(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Antes de la llamada al método: " + joinPoint.getSignature().getName());
    Object result = joinPoint.proceed(); // Llamada al método
    System.out.println("Después de la llamada al método");
    return result;
}

¿Por qué funciona esto?

AOP en Spring se basa en el uso de objetos proxy. Cuando llamas a un método, Spring sustituye tu implementación por un proxy que comprueba todos los aspectos asociados a ese método. Si el método coincide con un pointcut, Spring ejecuta el advice asociado.


Notas útiles:

  1. Las tareas transversales se resuelven muy bien con AOP. Ejemplos típicos:
    • Registro.
    • Gestión de transacciones.
    • Comprobación de seguridad.
    • Medición del tiempo de ejecución.
  2. No abuses de AOP! Tus aspectos deben ser ligeros y claros.
  3. Si la lógica se vuelve compleja, quizá los aspectos no sean la mejor solución.

Tabla: Resumen de términos AOP

Término Descripción Ejemplo
Aspecto Módulo que contiene comportamiento para tareas transversales Registro de llamadas a métodos
Pointcut Define dónde debe ejecutarse el aspecto execution(* com.example.service.*.*(..))
Advice Acción concreta ejecutada en los join points seleccionados Registro antes de la llamada al método (@Before)

Ahora entiendes cómo los aspectos (módulos) aplican sus acciones (advices) en puntos determinados (pointcuts). Hemos cubierto los conceptos básicos de AOP. En la siguiente clase veremos cómo aplicar estos conocimientos en la práctica para resolver problemas reales: registro, seguridad y gestión de transacciones. Mientras tanto, es importante entender que AOP no es simplemente magia de Spring, sino un mecanismo bien pensado con reglas claras de ejecución.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION