In the spring-native sample class-proxies-aop
in the branch sb-3.0.x
, the @Aspect
works when running in AOT mode, but not in a native-image.
There's no exception, the aspect just doesn't get executed.
Comment From: sdeleuze
Likely depends on #28115.
Comment From: snicoll
The proxy is now created properly but the aspect
smoke test still fails.
Comment From: sdeleuze
I was able to make it work with:
static class AspectRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(TestAspect.class,
builder -> builder.withMembers(MemberCategory.INVOKE_DECLARED_METHODS));
hints.proxies().registerJdkProxy(FactoryBean.class, BeanClassLoaderAware.class, ApplicationListener.class);
hints.proxies().registerJdkProxy(ApplicationAvailability.class, ApplicationListener.class);
}
}
Reflection hint should probably be inferred on Spring Framework side.
The 2 proxies are required by org.springframework.boot.availability.ApplicationAvailabilityBean
and org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar
and are not created automatically by my #28980 local fix (@jhoeller could you please confirm that's expected?). Related stacktrace is:
at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:48) ~[aspect:na]
at java.lang.reflect.Proxy.getProxyClass(Proxy.java:398) ~[aspect:na]
at org.springframework.util.ClassUtils.createCompositeInterface(ClassUtils.java:784) ~[na:na]
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getTargetShadowMatch(AspectJExpressionPointcut.java:437) ~[na:na]
at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:295) ~[na:na]
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:251) ~[na:na]
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:288) ~[na:na]
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:320) ~[na:na]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:366) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:318) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:435) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1757) ~[aspect:6.0.0-SNAPSHOT]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[aspect:6.0.0-SNAPSHOT]
If it is confirmed those can't be inferred, I guess those proxies hints should be contributed on Boot side
Comment From: sdeleuze
Looks like the aspect
smoke test samples now work, but there are other issues preventing it to work in a reliable fashion for various use case. #29519 is likely one of the blockers.
Comment From: sdeleuze
We should also check if aspect annotations and the methods and classes where they are applied are available via reflection, I suspect #29765 sample is broken by annotation not accessible via reflection on native.
Comment From: sdeleuze
We could potentially reuse Spring AOP infrastructure to identify the reflection entries needed to make aspects working out of the box. We could create a dedicated BeanFactoryInitializationAotProcessor
that would use BeanFactoryAspectJAdvisorsBuilder
to get the List<Advisor>
and process each of them. Maybe we could get the needed information for inference via instanceof PointcutAdvisor
and instanceof AbstractAspectJAdvice
checks.
Comment From: sdeleuze
Sorry for moving that again, but I won't have the bandwidth to tackle that in Spring 6.0 timeframe, so let's target 6.1.
Comment From: sdeleuze
This fix has been tested successfully with a few samples (including spring-aot-smoke-test/framework/aspect
one).
30529 repro is still broken for reasons that remain to be identified, but this will be handle via the dedicated issue.
Feedback welcome.
Comment From: snicoll
I believe this broke the batch AOT sample as follows:
Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/lang/annotation/Pointcut
at org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.<clinit>(AbstractAspectJAdvisorFactory.java:61)
at org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.<init>(BeanFactoryAspectJAdvisorsBuilder.java:60)
at org.springframework.aop.aspectj.annotation.AspectJBeanFactoryInitializationAotProcessor.processAheadOfTime(AspectJBeanFactoryInitializationAotProcessor.java:44)
at org.springframework.context.aot.BeanFactoryInitializationAotContributions.getContributions(BeanFactoryInitializationAotContributions.java:67)
at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:49)
at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:44)
at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
at org.springframework.context.aot.ContextAotProcessor.performAotProcessing(ContextAotProcessor.java:106)
at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:84)
at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:49)
at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
at org.springframework.boot.SpringApplicationAotProcessor.main(SpringApplicationAotProcessor.java:80)
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.annotation.Pointcut
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 14 more
The batch sample is failing. I don't know if it is special or if something else is involved.
Comment From: snicoll
Fixed by https://github.com/spring-projects/spring-framework/commit/74155e3d88faba9ee6815966b54a0ec34e7adf07