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
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
.