I am using Spring Boot 3.0.12. To enable load-time weaving.
A reproducible example is placed here. (branch - aspect
). To reproduce the issue do
curl --request GET 'http://localhost:8080/hello'
I have created an aop.xml
under META-INF
like below
<aspectj>
<aspects>
<aspect name="com.example.helloworld.aspects.DaoExceptionHandler"/>
<weaver options="-verbose -showWeaveInfo">
<include within="com.example.helloworld.*"/>
</weaver>
</aspects>
</aspectj>
I am starting the application with javaagent:/Users/dm/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar
.
Below dependencies are added in my pom.xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.20</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.20</version>
</dependency>
My aspect code is like below
@Aspect
@Slf4j
public class DaoExceptionHandler {
@AfterThrowing(
pointcut =
"execution(* *(..)) &&"
+ " @annotation(com.example.helloworld.utils.HandleDaoException)",
throwing = "ex")
public void handle(RuntimeException ex) {
log.error("Exception received on dao", ex);
throw JooqUtil.mapException(ex);
}
}
My usage of @HandleDaoException
is like below
@Component
public class DaoImpl {
@HandleDaoException
public void getError() {
throw new IllegalArgumentException("Test");
}
}
During my application startup, I see logs like below
2024-04-23T16:21:08.770+05:30 INFO 33973 --- [ main] c.e.helloworld.HelloWorldApplication : Started HelloWorldApplication in 0.797 seconds (process running for 1.13)
[MethodUtil@4b627298] info AspectJ Weaver Version 1.9.20 built on Tuesday Aug 15, 2023 at 23:35:34 PDT
[MethodUtil@4b627298] info register classloader sun.reflect.misc.MethodUtil@4b627298
[MethodUtil@4b627298] info using configuration /Users/debrajmanna/code/java/github/spring-boot-hello-world/target/classes/META-INF/aop.xml
[MethodUtil@4b627298] info register aspect com.example.helloworld.aspects.DaoExceptionHandler
When I annotate any method @HandleDaoException
, aspect is working correctly I see logs like below
java.lang.IllegalArgumentException: Test
at com.example.helloworld.dao.DaoImpl.getError(DaoImpl.java:10) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) ~[spring-aop-6.0.13.jar:6.0.13]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) ~[spring-aop-6.0.13.jar:6.0.13]
at com.example.helloworld.dao.DaoImpl$$SpringCGLIB$$0.getError(<generated>) ~[classes/:na]
at com.example.helloworld.controller.HelloWorldController.sendGreetings(HelloWorldController.java:17) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-6.0.13.jar:6.0.13]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[spring-webmvc-6.0.13.jar:6.0.13]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.0.13.jar:6.0.13]
...
If remove -javaagent
from my application startup command and also specify @EnableAspectJAutoProxy
then also I see the above stack-trace when DaoExceptionHandler
is invoked.
My understanding is without load time weaving spring defaults to CGLIB proxies. From the above exception stack trace it looks like CGLIB proxies are still getting used even though load time weaving is enabled. If my understanding is wrong then is there a way for me to know if load time weaving is working properly in spring or not?
You made two mistakes in your project. I fixed them in this PR:
Do not use @Import({ DaoExceptionHandler.class })
, because it makes Spring treat the native AspectJ aspect like a Spring @Configuration
class, falsely creating a special type of CGLIB proxy for it. That CGLIB proxy is not a regular Spring AOP proxy, but a different type for Spring configs with a different behaviour. See here for an explanation. Anyway, you do not need that, and it is also wrong.
Make sure to set the correct aspect weaving scope com.example.helloworld..*
, where the double-dot notation includes sub-packages, too.