We are using a combination of XML and Annotation configuration in a Spring web application. After upgrading to Spring 5.3.1 (from Spring 4), some classes are not processed by the AspectJ Load Time Weaver. In our XML configuration we have:

<context:component-scan base-package="com.acme.spring"/>
<context:load-time-weaver aspectj-weaving="on" />

But AspectJ weaving only works for a subset of all classes. In particular, it does not work for classes found by component-scan. If the same bean is declared in XML, it works as expected.

We have managed to condense it into a small sample application:

https://github.com/emillundstrm/springaspectjtest

Running mvn jetty:run you will find that there is no message about com.acme.spring.TestBean being woven.

However, if you remove the @Component annotation from TestBean and instead declare it in ApplicationContext.xml, this is logged:

[WebAppClassLoader@58437801] debug weaving 'com.acme.spring.TestBean'
[WebAppClassLoader@58437801] weaveinfo Join point 'method-execution(void com.acme.spring.TestBean.run())' in Type 'com.acme.spring.TestBean' (TestBean.java:11) advised by around advice from 'org.springframework.transaction.aspectj.AnnotationTransactionAspect' (AbstractTransactionAspect.aj:66)
[WebAppClassLoader@58437801] debug generating class 'com.acme.spring.TestBean$AjcClosure1'

A workaround is using aspectjweaver.jar as -javaagent, but that is inconvenient if you don't control the JVM flags.

Comment From: weaselmetal

Ha, came here by chance. Isn't it the case that jetty is one of the servlet containers that doesn't contain a load time weaver and therefore requires a java agent? See this piece of information I read just yesterday: https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/aop.html#aop-aj-ltw-environment-generic

Comment From: emillundstrm

Ha, came here by chance. Isn't it the case that jetty is one of the servlet containers that doesn't contain a load time weaver and therefore requires a java agent? See this piece of information I read just yesterday: https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/aop.html#aop-aj-ltw-environment-generic

If this were the case, there'd be an error similar to:

java.lang.IllegalStateException: ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-instrument-{version}.jar

But this is not the case. There is no error, because Jetty 9.x provides addTransformer.

And it wouldn't explain why it works from XML, but not from annotations.

Comment From: emillundstrm

I believe the difference from beans defined by @Component and XML stems from this code in ConfigurationClassPostProcessor:

if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
    // Configuration class (full or lite) or a configuration-derived @Bean method
    // -> resolve bean class at this point...
    AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
    if (!abd.hasBeanClass()) {
        try {
            abd.resolveBeanClass(this.beanClassLoader);
        }
        catch (Throwable ex) {
            throw new IllegalStateException(
                "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
        }
    }
}

The XML bean has null configClassAttr, while the annotation bean has the value "lite". This causes the annotated bean class to be resolved, which is seemingly too early for the AspectJ LoadTimeWeaver to be active.

Comment From: goetzseb

Hey guys.

I stumbled across this searching for a solution to my problem which I have reported today on stackoverflow. Reading the issue description this seems to be the same issue I have. Same situation: upgrade from 4.3.14 to 5.3.3 under Tomcat 9. Only few classes are being woven. But until now I was not able to figure out which one did work.

I can confirm the workaround with the aspectjweaver agent is working, but not applicable for my use case.

Has there been any progress made on this or is there another workaround than the one with the javaagent?

Comment From: andrei-ivanov

AFAIK, this was the workaround, from the days of the application servers, which would deploy multiple applications and you could not install a JVM agent that would affect all, while in the modern days, the agent is the recommended way.

Comment From: goetzseb

For me this is quite a problem as the -javaagent:aspectjweaver.jar approach rises the server startup to four times the normal duration (60sec. vs 250sec.). The class loading mechanism or the weaving must have changed somewhere between 5.1.20.RELEASE and 5.2.0.RELEASE. But I am not deep enough into the spring framework to investigate this any further.

Comment From: sbrannen

@emillundstrm, thanks for sharing your analysis.

The XML bean has null configClassAttr, while the annotation bean has the value "lite". This causes the annotated bean class to be resolved, which is seemingly too early for the AspectJ LoadTimeWeaver to be active.

If that's the case, this might be a regression caused by the changes in 40c62139ae6f8faa09fc0047ebc8ec65c5a2e809, stemming from the fact that a @Component class that is picked up via @ComponentScan is considered to be a candidate configuration class in "lite" mode (i.e., without the @Configuration annotation and even without any @Bean methods) and therefore has its class eagerly loaded.

@jhoeller, thoughts?

Comment From: mcolbert-unicon

Ran into this issue yesterday. We upgraded to 5.2.12 recently and noticed yesterday that our app would stop working after a while in our test environment. Threads were waiting on database connections from the connection pool. It turns out that our @Transactional beans were no longer being advised by org.springframework.transaction.aspectj.AnnotationTransactionAspect and therefore none of our connections were transactional. Glad we caught it and glad there is a fix coming. We dropped back to 5.1.20 based on the reporting by @goetzseb.

Comment From: sbrannen

Has there been any progress made on this

We will be working on a fix for Spring Framework 5.3.5 and potentially backporting to 5.2.14.

or is there another workaround than the one with the javaagent?

Well, I haven't tried this out, but based on my initial analysis of the regression, it appears that annotating your class with @javax.inject.Named instead of @Component or @Service might be a viable workaround. Note, however, that this workaround would not apply to replacing @Controller, @RestController, or @Repository with @Named.

@goetzseb, please try annotating some of your component scanned classes with @Named and let us know if that works for you as an interim solution.

Comment From: sbrannen

I have confirmed that this is a regression introduced in Spring Framework 5.2.0.

Well, I haven't tried this out, but based on my initial analysis of the regression, it appears that annotating your class with @javax.inject.Named instead of @Component or @Service might be a viable workaround. Note, however, that this workaround would not apply to replacing @Controller, @RestController, or @Repository with @Named.

Using @Named instead of @Component or @Service works with component scanning.

I have also confirmed that the mere presence or meta-presence of @Component on a bean will result in the reported behavior, even if the bean is not registered via component scanning.

Comment From: sbrannen

This regression has been fixed in master and 5.2.x.

Feel free to try it out in the upcoming snapshots for Spring Framework 5.3.5 and 5.2.14, and please report back on whether it works for you.

Comment From: goetzseb

Great to hear and thank you very much!

Comment From: pdeneve

This regression has been fixed in master and 5.2.x.

Feel free to try it out in the upcoming snapshots for Spring Framework 5.3.5 and 5.2.14, and please report back on whether it works for you.

@sbrannen Doesn't work for me in either versions. It can be reproduced by cloning this repo, checking out branch 5.3.5 or 5.2.14 and running mvn test -pl spring.ltw.