Ahora toca hablar de los escollos: qué errores pueden aparecer al usar AOP, cómo evitarlos y cómo configurar los aspectos correctamente para que sean eficaces y fiables.
Problema 1: los aspectos no se aplican
Este es el caso más común que puede volver loco a cualquier desarrollador. Has escrito tu aspecto perfecto, configurado los pointcuts, probado... pero simplemente no se activa. ¿Por qué?
- Razón 1: tu aspecto puede no estar registrado en el contexto de Spring. Por ejemplo, si olvidaste la anotación
@EnableAspectJAutoProxyen tu configuración. - Razón 2: sintaxis incorrecta en los pointcuts. Un carácter perdido y tu aspecto deja de funcionar.
- Razón 3: problemas de visibilidad. Por ejemplo, los métodos que se llaman dentro de la misma clase pueden ignorar los aspectos por el mecanismo de proxies de Spring (pero de esto hablaremos más adelante).
Ejemplo de configuración incorrecta:
// Anotación @EnableAspectJAutoProxy olvidada
@Configuration
@ComponentScan(basePackages = "com.example.aop")
public class AppConfig {
// Configuración del aspecto, pero sin activar AOP
}
¿Cómo arreglarlo? Añade @EnableAspectJAutoProxy:
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.example.aop")
public class AppConfig {
// ¡Ahora AOP funcionará!
}
Problema 2: duplicación de ejecuciones de los aspectos
Otro dolor de cabeza: tu aspecto de repente se ejecuta dos veces o más. Puede pasar por llamadas anidadas o porque la configuración intercepta los mismos join points varias veces.
Ejemplo:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Before method execution");
}
@Before("execution(* com.example.service.*.*(..))")
public void anotherLogBefore() {
System.out.println("Another before method execution");
}
}
En este caso, cada método en com.example.service disparará ambos @Before. ¿Solución? Revisa tus pointcuts para que sean únicos y únelos lógicamente si es posible.
Problema 3: error al aplicar aspectos a métodos privados
Spring AOP no intercepta llamadas a métodos privados (porque funciona vía proxies, que no pueden sustituir métodos privados).
Ejemplo:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(private * com.example.service.*.*(..))")
public void logPrivateMethods() {
System.out.println("This won't work!");
}
}
¿Solución? Haz el método public o usa AspectJ (pero esa es otra historia). Spring AOP sólo funciona con métodos públicos.
Problema 4: problemas de rendimiento
Si los aspectos se aplican con frecuencia y a grandes volúmenes de código, pueden ralentizar la aplicación. Por ejemplo, si interceptas todos los métodos en un paquete y registras cada ejecución — échale un vistazo a la consola y mira cuántas veces se ejecuta tu aspecto.
Ejemplo:
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println(joinPoint.getSignature() + " took " + (end - start) + " ms");
return result;
}
}
No conviene aplicar ese aspecto en todas partes — elige los métodos clave.
Recomendaciones para configurar los aspectos
Para evitar los problemas anteriores, sigue estas recomendaciones:
Elección correcta del Pointcut
No apliques aspectos a lo loco a todos los métodos de tu aplicación. Usa filtros claros.
Ejemplo: en vez de execution(* *(..)), que intercepta TODO, especifica tus pointcuts:
@Pointcut("execution(public * com.example.service.MyService.*(..))")
public void serviceMethods() {}
Limitar el alcance de los aspectos
Si un aspecto realiza una tarea pesada (por ejemplo, escribir en la base de datos o hacer llamadas a una API), limita su acción a los join points estrictamente necesarios.
Ejemplo:
@Pointcut("within(com.example.controller..*)")
public void controllerLayer() {}
@Pointcut("execution(* com.example.service.MyService.importantMethod(..))")
public void importantServiceMethod() {}
@Pointcut("controllerLayer() || importantServiceMethod()")
public void limitedScope() {}
Establecer el orden de ejecución de los aspectos
Si tienes varios aspectos que pueden interceptar los mismos métodos, define el orden de ejecución con la anotación @Order.
Ejemplo:
@Aspect
@Component
@Order(1)
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void log() {
System.out.println("Logging first!");
}
}
@Aspect
@Component
@Order(2)
public class SecurityAspect {
@Before("execution(* com.example.service.*.*(..))")
public void secure() {
System.out.println("Security check second!");
}
}
Registra errores y aspectos
Para depurar bien, es útil registrar los aspectos. Usa librerías como SLF4J para eso.
Ejemplo:
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void logException(Exception ex) {
logger.error("Exception thrown: ", ex);
}
}
Testea los aspectos
Usa unit tests para comprobar que tus aspectos se activan sólo donde deben.
Ejemplo de test:
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggingAspectTest {
@Autowired
private MyService myService;
@Test
public void testLoggingAspect() {
myService.someMethod();
// Comprueba que se haya registrado el log
// Esto se puede hacer con mocks y comprobando la llamada al logger
}
}
¿Cómo configurar correctamente los aspectos?
Para hacerlo fácil, aquí tienes una checklist para configurar bien los aspectos:
- Asegúrate de que
@EnableAspectJAutoProxyestá añadida en la configuración. - Revisa todos tus pointcuts para verificar que sean correctos. Usa tests pequeños para depurarlos.
- Limita la acción de los aspectos solo a los join points necesarios.
- Configura el orden de ejecución de los aspectos (
@Order) si hay varios. - Usa logging para rastrear el funcionamiento de los aspectos.
- Añade unit tests para los aspectos, para garantizar que se activan como se espera.
Ahora estás armado con todo lo necesario para evitar errores típicos y configurar bien los aspectos en tu aplicación. Usa AOP con cabeza, y te facilitará la vida — ¡promesa de Spring! 😉
GO TO FULL VERSION