spring-projects / spring-projects/spring-framework

Native Image + Quartz SchedulerBeanFactory + Spring AOP Advisor: Uses wrong CGLIB class

Open
#33,835 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: core status: waiting-for-triage
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

Use case example:

  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public Advisor schedulerFactoryBeanAdvisor() {
    final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("execution(* org.springframework.scheduling.quartz.SchedulerFactoryBean.*(..)");
    return new DefaultPointcutAdvisor(pointcut, (MethodInterceptor) invocation -> {
        log.info("Intercepted!"); // do something
        return invocation.proceed();
    });
  }

With the above, AOT generates class org.springframework.scheduling.quartz.SchedulerFactoryBean$$SpringCGLIB$$0, all as expected.
The native image build also works without any issue.
However, running the generated application then results in the following error:

Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler': Unexpected AOP exception
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:607)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:969)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
	at com.some.application.Application.main(Application.java:14)
Caused by: org.springframework.aop.framework.AopConfigException: Unexpected AOP exception
	at org.springframework.aop.framework.CglibAopProxy.buildProxy(CglibAopProxy.java:236)
	at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:163)
	at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildProxy(AbstractAutoProxyCreator.java:519)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:466)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:371)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:320)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:438)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1809)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
	... 15 more
Caused by: java.lang.UnsupportedOperationException: CGLIB runtime enhancement not supported on native image. Make sure to include a pre-generated class on the classpath instead: org.springframework.scheduling.quartz.SchedulerFactoryBean$$SpringCGLIB$$1
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
	at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:575)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.lambda$new$1(AbstractClassGenerator.java:107)
	at org.springframework.cglib.core.internal.LoadingCache.lambda$createEntry$1(LoadingCache.java:52)
	at java.base@17.0.9/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:57)
	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:130)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:317)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:562)
	at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:407)
	at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:62)
	at org.springframework.aop.framework.CglibAopProxy.buildProxy(CglibAopProxy.java:221)
	... 24 more

Note that it is trying to use org.springframework.scheduling.quartz.SchedulerFactoryBean$$SpringCGLIB$$1 instead of the generated one $$SpringCGLIB$$0.

Thanks in advance for having a look, let me know if the issue is on my side -- maybe I am declaring the Advisor incorrectly or missing some Hints? But I do have other uses of Advisor that are working just fine, only this one causes an issue...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with org.springframework.aop.framework.CglibAopProxy.buildProxy and ObjenesisCglibAopProxy.createProxyClassAndInstance, then compare the generated SchedulerFactoryBean$$SpringCGLIB$$0 with the runtime request for $$1. Reproduce the native-image startup failure with the supplied Advisor and verify that the application uses the pre-generated class and starts without the CGLIB runtime-enhancement exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.