To enable AspectJ load time weaving in a Spring application, one would use the @EnableLoadTimeWeaving annotation as outlined in the Spring reference documention. Due to issue 29609 this is not working and a workaround proposed involves registering AspectJWeavingEnabler and DefaultContextLoadTimeWeaver upfront when instantiating the application context. For a spring boot application, this looks as follows:

SpringApplication.run(new Class[] { Config.class, AspectJWeavingEnabler.class, MyLoadTimeWeaver.class }, args);

With MyLoadTimeWeaver extending DefaultContextLoadTimeWeaver and annotated with @Component("loadTimeWeaver") because the name of the LoadTimeWeaver bean "loadTimeWeaver" is expected by the framework.

When running the application, some auto-configured beans cannot be accessed anymore. E.g. for the spring.boot.ltw module in this repository, the following stacktrace is produced:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:550) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-3.1.2.jar:3.1.2]
        at be.pdn.training.aspectj.spring.boot.ltw.Main.main(Main.java:9) ~[classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:605) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:888) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-6.0.11.jar:6.0.11]
        ... 19 common frames omitted
Caused by: java.lang.IllegalAccessError: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor.postProcessBeforeInitialization(JdbcConnectionDetailsBeanPostProcessor.java:54) ~[spring-boot-autoconfigure-3.1.2.jar:3.1.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.11.jar:6.0.11]
        ... 29 common frames omitted

To reproduce yourself:

  • Clone this repository
  • Checkout branch spring_boot_issue
  • Execute mvn exec:exec -pl spring.boot.ltw

It is possible to workaround this issue by defining manually the beans for which an IllegalAccessError occurs. E.g. for the sample project, uncomment the @Bean annotation for the JdbcConnectionDetails bean in Config.java and it will work.

Comment From: pop1213

It seems that the issue is caused by the jdbcConnectionDetailsHikariBeanPostProcessor bean being loaded by the temp classloader. When this bean's class is loaded in advance (e.g., Main.class.getClassLoader().loadClass("org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari") ), the problem does not occur. Additionally, I have observed that when @Bean is used on a static method, the classloader for this bean becomes the temp classloader instead of the bean classloader. This is clearly incorrect, as the bean should not be loaded by the temp classloader.

Comment From: pop1213

https://github.com/spring-projects/spring-framework/issues/14839

It might be the same issue.

Comment From: wilkinsona

Thanks for the analysis, @pop1213.

Additionally, I have observed that when @Bean is used on a static method, the classloader for this bean becomes the temp classloader instead of the bean classloader.

This sounds incorrect to me too but it is out of Spring Boot's control. @pdeneve You may want to comment on https://github.com/spring-projects/spring-framework/issues/14839. Alternatively, if you think that your issue may not be quite the same problem, you may want to open a separate Spring Framework issue.

Comment From: pdeneve

@wilkinsona Difficult to say if https://github.com/spring-projects/spring-framework/issues/14839 has the same root cause as this issue. It smells the same, but might not taste the same. Hence I've created a new issue in the spring-framework project.