Affects: Spring Framework 5.3.4

When I use the @EnableLoadTimeWeaving annotation, beans will not be woven, but using XML configuration <context:load-time-weaver/> can be successfully woven.

Here's a snippet that use @EnableLoadTimeWeaving annotation:

@ComponentScan({"com.example.demo","foo"})
@EnableLoadTimeWeaving
public class LwtStart {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(LwtStart.class);
        //ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        //a bean annotated by @Component
        EntitlementCalculationService service1=ctx.getBean(EntitlementCalculationService.class);
        service1.calculateEntitlement();


        //A simple object that is not managed by the Spring container ,not annotated by @Component
        EntitlementCalculationService service2=new MyEntitlementCalculationService();
        //For comparison,to prove load-time-weaver takes effect
        service2.calculateEntitlement();
    }
}

aop.xml

<aspectj>
    <weaver options="-debug">
        <!-- only weave classes in our application-specific packages -->
        <include within="foo.*"/>
        <include within="com.example.demo.ltw.aspect.*"/>
    </weaver>

    <aspects>
        <!-- weave in just this aspect -->
        <aspect name="com.example.demo.ltw.aspect.ProfilingAspect"/>
    </aspects>
</aspectj>

the aspect

@Around("methodsToBeProfiled()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
    StopWatch sw = new StopWatch(getClass().getSimpleName());
    try {
        System.out.println(pjp.getTarget());
        sw.start(pjp.getSignature().getName());
        return pjp.proceed();
    } finally {
        sw.stop();
        System.out.println(sw.prettyPrint());
    }
}

@Pointcut("execution(public * foo.*.*(..))")
public void methodsToBeProfiled(){}

In this simple case, the EntitlementCalculationService object that was successfully woven will print the execution time . As mentioned before, service2 prints the execution time, service1 does not, proving that it was not successfully woven.

When switching to the XML configuration method, both service1 and service2 can be successfully woven, and they can both print the execution time.

// AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(LwtStart.class);
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");

EntitlementCalculationService service1=ctx.getBean(EntitlementCalculationService.class);
service1.calculateEntitlement();

EntitlementCalculationService service2=new MyEntitlementCalculationService();
service2.calculateEntitlement();
<!-- a service object; we will be profiling its methods -->
<bean id="entitlementCalculationService"
      class="foo.StubEntitlementCalculationService"/>

<!-- this switches on the load-time weaving -->
<context:load-time-weaver aspectj-weaving="on"/>

When using Java configuration, the AspectJWeavingEnabler.enableAspectJWeaving method will not be called until Spring loads the bean classes, which seems to be the reason why @EnableLoadTimeWeaving does not take effect.

Comment From: pop1213

spring-ltw.zip

Comment From: sbrannen

This appears to be a duplicate of #26199.

I am therefore closing this issue.

If you find that the issue still exists after upgrading to Spring Framework 5.3.5 or 5.3.6, please post back here as a comment, and we will investigate further.

Comment From: pop1213

This appears to be a duplicate of #26199.

I am therefore closing this issue.

If you find that the issue still exists after upgrading to Spring Framework 5.3.5 or 5.3.6, please post back here as a comment, and we will investigate further.

After I upgraded Spring to the latest version(5.3.6), this problem still exists. Although the bean class is not loaded earlier in the ConfigurationClassPostProcessor, it is still before AspectJWeavingEnabler.enableAspectJWeaving method is called(As far as I know, it is the key code that causes the load time weaver to work).

I found through debug mode that in the process of instantiating LoadTimeWeavingConfiguration, it will call the DefaultListableBeanFactory#doGetBeanNamesForType method when it resolves dependencies, which will cause all bean classes to be loaded in advance.

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        List<String> result = new ArrayList<>();

        // Check all bean definitions.
        for (String beanName : this.beanDefinitionNames) {
            // Only consider bean as eligible if the bean name is not defined as alias for some other bean.
            if (!isAlias(beanName)) {
                try {
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    // Only check bean definition if it is complete.
                    if (!mbd.isAbstract() && (allowEagerInit ||
                            (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                                    !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
//**************************This line of code will cause other bean classes to be loaded*******************                      
                        boolean isFactoryBean = isFactoryBean(beanName, mbd);

I think this may be the cause of the load time weaver not working. Hope to get your reply , thank you very much.

Comment From: pop1213

@sbrannen

Comment From: sbrannen

After I upgraded Spring to the latest version(5.3.6), this problem still exists.

Thanks for looking into it and providing feedback.

We have reopened this issue and will investigate the cause.

Comment From: sbrannen

When I use the @EnableLoadTimeWeaving annotation, beans will not be woven, but using XML configuration <context:load-time-weaver/> can be successfully woven.

Did it work for your application using @EnableLoadTimeWeaving in a version of Spring Framework prior to 5.3.4?

If so, which version?

Comment From: pop1213

When I use the @EnableLoadTimeWeaving annotation, beans will not be woven, but using XML configuration <context:load-time-weaver/> can be successfully woven.

Did it work for your application using @EnableLoadTimeWeaving in a version of Spring Framework prior to 5.3.4?

If so, which version?

Sorry, I haven't tried any version before 5.3.4 so far

Comment From: sbrannen

Sorry, I haven't tried any version before 5.3.4 so far

OK. Thanks for the feedback.

I was asking in order to confirm if this is a "regression", but since you don't know that we might discover that this scenario never worked.

Comment From: fsgonz

@sbrannen I think there was a problem in this commit. You are not taking into account the includeNonSingletons parameter after this change. The same that was mentioned above.

Is there a rationale for that or is it a bug? we have a change of behavior because of this. Is this still opened?

This verification was missed I think.

Comment From: sbrannen

Please note that #28616 has been resolved for Spring Framework 5.3.21, scheduled for release later this week.

@pop1213, please let us know if the fix in #28616 also resolves your issue.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Comment From: pdeneve

Please note that #28616 has been resolved for Spring Framework 5.3.21, scheduled for release later this week.

@pop1213, please let us know if the fix in #28616 also resolves your issue.

@sbrannen The issue is not resolved in Spring Framework 5.3.21. It can be reproduced by cloning this repo, checking out branch 5.3.21 and running mvn test -pl spring.ltw.