A reproducible project is placed here. (Branch - aspect_autowire
) .Invoke the below command to reproduce the problem
curl --request GET 'http://localhost:8080/hello'`
My aspect is code is like below
@Aspect
@Slf4j
@AllArgsConstructor
@Component
public class DaoExceptionHandler {
private final Map<Long, String> errorLogMap;
@AfterThrowing(
pointcut =
"execution(* *(..)) &&"
+ " @annotation(com.example.helloworld.utils.HandleDaoException)",
throwing = "ex")
public void handle(RuntimeException ex) {
errorLogMap.put(System.currentTimeMillis(), ex.getMessage());
log.error("Exception received on dao", ex);
log.error("Error Log Map Content: {}", errorLogMap);
throw JooqUtil.mapException(ex);
}
}
errorLogMap
bean is defined like below
@Configuration
@Slf4j
@EnableLoadTimeWeaving
public class AspectConfig {
@Bean
public Map<Long, String> errorLogMap() {
log.info("Initialising Bean");
return new HashMap();
}
}
aop.xml
is placed in src/main/resources/META-INF
and is like below
<aspectj>
<aspects>
<aspect name="com.example.helloworld.aspects.DaoExceptionHandler"/>
<weaver options="-verbose -showWeaveInfo">
<include within="com.example.helloworld..*"/>
</weaver>
</aspects>
</aspectj>
-javaagents
are specified like below while running the application
-Djava.rmi.server.hostname=localhost -javaagent:/Users/debrajmanna/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar -javaagent:/Users/debrajmanna/.m2/repository/org/springframework/spring-instrument/6.0.13/spring-instrument-6.0.13.jar
During startup I see logs like below
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
[AppClassLoader@251a69d7] info AspectJ Weaver Version 1.9.20 built on Tuesday Aug 15, 2023 at 23:35:34 PDT
[AppClassLoader@251a69d7] info register classloader jdk.internal.loader.ClassLoaders$AppClassLoader@251a69d7
[AppClassLoader@251a69d7] info using configuration /Users/debrajmanna/code/java/github/spring-boot-hello-world/target/classes/META-INF/aop.xml
[AppClassLoader@251a69d7] info register aspect com.example.helloworld.aspects.DaoExceptionHandler
...
2024-04-28T15:15:20.616+05:30 INFO 87296 --- [ main] c.e.helloworld.HelloWorldApplication : No active profile set, falling back to 1 default profile: "default"
[AppClassLoader@251a69d7] weaveinfo Join point 'method-execution(void com.example.helloworld.dao.DaoImpl.getError())' in Type 'com.example.helloworld.dao.DaoImpl' (DaoImpl.java:10) advised by afterThrowing advice from 'com.example.helloworld.aspects.DaoExceptionHandler' (DaoExceptionHandler.java)
...
[MethodUtil@3209a8de] info AspectJ Weaver Version 1.9.20 built on Tuesday Aug 15, 2023 at 23:35:34 PDT
[MethodUtil@3209a8de] info register classloader sun.reflect.misc.MethodUtil@3209a8de
[MethodUtil@3209a8de] info using configuration /Users/debrajmanna/code/java/github/spring-boot-hello-world/target/classes/META-INF/aop.xml
[MethodUtil@3209a8de] info register aspect com.example.helloworld.aspects.DaoExceptionHandler
But aspect code is not all getting invoked. I can just see
2024-04-28T15:17:36.104+05:30 WARN 87296 --- [nio-8080-exec-2] c.e.h.controller.HelloWorldController : Ignoring exception
If I just comment the usage of errorLogMap in DaoExceptionHandler
public class DaoExceptionHandler {
// private final Map<Long, String> errorLogMap;
@AfterThrowing(
pointcut =
"execution(* *(..)) &&"
+ " @annotation(com.example.helloworld.utils.HandleDaoException)",
throwing = "ex")
public void handle(RuntimeException ex) {
// errorLogMap.put(System.currentTimeMillis(), ex.getMessage());
log.error("Exception received on dao", ex);
// log.error("Error Log Map Content: {}", errorLogMap);
throw JooqUtil.mapException(ex);
}
}
I can see the aspect code getting invoked.
2024-04-28T15:19:32.100+05:30 ERROR 88735 --- [nio-8080-exec-1] c.e.h.aspects.DaoExceptionHandler : Exception received on dao
java.lang.IllegalArgumentException: Test
at com.example.helloworld.dao.DaoImpl.getError(DaoImpl.java:10) ~[classes/:na]
at com.example.helloworld.controller.HelloWorldController.sendGreetings(HelloWorldController.java:17) ~[classes/:na]
...
If I specify @EnableAspectJAutoProxy
in place of EnableLoadTimeWeaving
in AspectConfig
and remove both javaagent
then errorLogMap()
is getting correctly injected into DaoExceptionHandler
and the aspect is also getting invoked.
With @EnabledLoadTimeWeaving
I tried adding only aspectjweaver-1.9.20.jar
as -javaagent. But it was not not helping. So added spring-instrument.jar
also as -javaagent
. But that is also not helping. Can someone suggest if it is possible to use spring beans with load-time weaving of aspects?
The Spring documentation for @Configurable
might be helpful, like I said. There is also a Baeldung tutorial.
You need
spring-aspects
dependency,@EnableSpringConfigured
in your config class,@Autowired
in your aspect.The Lombok-generated @AllArgsConstructor
does not use @Autowired
or @Inject
, which is why constructor injection does not work. Besides, the @Component
annotation is also wrong for native aspects. You only need that for Spring AOP aspects.
See my pull request for details.
P.S.: I also removed @EnableLoadTimeWeaving
in favour of only -javaagent:/path/to/aspectjweaver.jar
, because this way the aspect weaver is attached earlier. Hot-attachment via @EnableLoadTimeWeaving
and spring-instrument
is nice, but less reliable (not working for all classloaders) and ready for action later.