Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InstantiationAwareBeanPostProcessor implementations are not invoked with an AOT-processed context #28777

Closed
christophstrobl opened this issue Jul 8, 2022 · 8 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Milestone

Comments

@christophstrobl
Copy link
Member

Obtaining a bean provided by a configuration class that has dependencies caused trouble during AOT processing.

The Boot Configuration for JdbcRepositoriesAutoConfiguration contains a conditional configuration class SpringBootJdbcConfiguration depending on the ApplicationContext.

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(AbstractJdbcConfiguration.class)
static class SpringBootJdbcConfiguration extends AbstractJdbcConfiguration {

    private final ApplicationContext applicationContext;

    SpringBootJdbcConfiguration(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
        return new EntityScanner(this.applicationContext).scan(Table.class);
    }

}

The AbstractJdbcConfiguration exposes a bean of type RelationalManagedTypes

@Bean
public RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException {
	return RelationalManagedTypes.fromIterable(getInitialEntitySet());
}

Obtaining jdbcManagedTypes via registeredBean.getBeanFactory().getBean(registeredBean.getBeanName(), ManagedTypes.class)) within a BeanRegistrationAotProcessor errors with

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration$SpringBootJdbcConfiguration': Failed to instantiate [org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration$SpringBootJdbcConfiguration]: No default constructor found
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1305)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1197)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:393)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1323)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:566)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:526)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
	at org.springframework.data.aot.ManagedTypesBeanRegistrationAotProcessor.processAheadOfTime(ManagedTypesBeanRegistrationAotProcessor.java:57)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 8, 2022
@sbrannen sbrannen added in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing labels Jul 8, 2022
@sbrannen sbrannen added this to the Triage Queue milestone Jul 8, 2022
@snicoll
Copy link
Member

snicoll commented Jul 11, 2022

I am not sure I got all those pieces together. Can you please share how I can reproduce this myself? Also, if that exception below is happening at build time, I don't think that's right. We shouldn't be instantiating beans at build time like that.

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Jul 11, 2022
@christophstrobl
Copy link
Member Author

@snicoll build either the data-jdbc or data-cassandra sample from this PR spring-attic/spring-native#1664

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 12, 2022
@snicoll
Copy link
Member

snicoll commented Jul 12, 2022

Can you clarify that the bean is instantiated at build time and why that is ?

@christophstrobl
Copy link
Member Author

The bean serves as an entry point for domain type inspection of the data module which will add reflection configuration etc.

@snicoll snicoll changed the title Configuration class constructor arguments should be resolved during aot phase. InstantiationAwareBeanPostProcessor are not invoked with an AOT-processed context Jul 12, 2022
@snicoll
Copy link
Member

snicoll commented Jul 12, 2022

What happens is that InstantiationAwareBeanPostProcessor is not honored when a GenericApplicationContext is refreshed for AOT processing. As a result, determineCandidateConstructors is not invoked and the bean definition does not contain the constructor to use.

We're in a weird state right now as we're not actively preventing beans to be instantiated, but the configuration of the BeanFactory is not complete to do so properly.

@snicoll snicoll changed the title InstantiationAwareBeanPostProcessor are not invoked with an AOT-processed context InstantiationAwareBeanPostProcessor implementations are not invoked with an AOT-processed context Jul 12, 2022
@snicoll snicoll added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Jul 20, 2022
@snicoll snicoll modified the milestones: Triage Queue, 6.0.0-M6 Jul 20, 2022
@snicoll snicoll self-assigned this Jul 20, 2022
snicoll added a commit to snicoll/spring-framework that referenced this issue Jul 20, 2022
@snicoll
Copy link
Member

snicoll commented Jul 20, 2022

I have some code that supports the use case described above. This also includes honoring autowired injection points as well as initialization in case the @Configuration class needs to check something before producing beans.

I've kept the very conservative approach to only include MergedBeanDefinitionPostProcessor instances which happen to be the same than we need for the above. Now that those are registered as post processors, the context will try to post process the bean definition again, unless a package-level postProcessed flag is set on the RootBeanDefinition. Unfortunately, that logic is in a separate module so I don't know yet how to fix that.

Current code (and test) are available in 35da93c

@OlgaMaciaszek

This comment was marked as outdated.

@snicoll
Copy link
Member

snicoll commented Jul 25, 2022

Having tried to fix the problem above in several ways, we've decided to resort to a double invocation of MBDPP if a bean is instantiated at build-time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants