Don't implicitly filter all AOT processor beans

Update `BeanDefinitionMethodGeneratorFactory` to not implicitly filter
AOT processor beans if they also implement
`BeanRegistrationExcludeFilter`.

Most AOT processor beans generate code that replaces themselves, so
implicitly filtering them is the right thing to do. However, some beans
may need to perform AOT processing and still get registered when the
AOT processed application runs. These beans can now additionally
implement `BeanRegistrationExcludeFilter` to signal that they should
not be implicitly filtered.

Closes gh-28526
This commit is contained in:
Phillip Webb 2022-05-26 20:59:50 -07:00
parent efa8ffb728
commit 6f71328ba6
4 changed files with 69 additions and 0 deletions

View File

@ -114,6 +114,9 @@ class BeanDefinitionMethodGeneratorFactory {
private boolean isImplicitlyExcluded(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
if (BeanRegistrationExcludeFilter.class.isAssignableFrom(beanClass)) {
return false;
}
return BeanFactoryInitializationAotProcessor.class.isAssignableFrom(beanClass)
|| BeanRegistrationAotProcessor.class.isAssignableFrom(beanClass);
}

View File

@ -22,6 +22,10 @@ import org.springframework.aot.generate.GenerationContext;
* AOT contribution from a {@link BeanFactoryInitializationAotProcessor} used to
* initialize a bean factory.
*
* <p>Note: Beans implementing interface will not have registration methods
* generated during AOT processing unless they also implement
* {@link org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter}.
*
* @author Phillip Webb
* @since 6.0
* @see BeanFactoryInitializationAotProcessor

View File

@ -23,6 +23,10 @@ import org.springframework.lang.Nullable;
* AOT processor that makes bean factory initialization contributions by
* processing {@link ConfigurableListableBeanFactory} instances.
*
* <p>Note: Beans implementing interface will not have registration methods
* generated during AOT processing unless they also implement
* {@link org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter}.
*
* @author Phillip Webb
* @since 6.0
* @see BeanFactoryInitializationAotContribution

View File

@ -18,6 +18,7 @@ package org.springframework.beans.factory.aot;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RegisteredBean;
@ -109,6 +110,34 @@ class BeanDefinitionMethodGeneratorFactoryTests {
.containsExactly(beanContribution, loaderContribution);
}
@Test
void getBeanDefinitionMethodGeneratorWhenRegisteredBeanIsAotProcessorFilteresBean() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("test1", BeanDefinitionBuilder
.rootBeanDefinition(TestBeanFactoryInitializationAotProcessorBean.class).getBeanDefinition());
RegisteredBean registeredBean1 = RegisteredBean.of(beanFactory, "test1");
beanFactory.registerBeanDefinition("test2", BeanDefinitionBuilder
.rootBeanDefinition(TestBeanRegistrationAotProcessorBean.class).getBeanDefinition());
RegisteredBean registeredBean2 = RegisteredBean.of(beanFactory, "test2");
BeanDefinitionMethodGeneratorFactory methodGeneratorFactory = new BeanDefinitionMethodGeneratorFactory(
new AotFactoriesLoader(beanFactory, springFactoriesLoader));
assertThat(methodGeneratorFactory.getBeanDefinitionMethodGenerator(registeredBean1, null)).isNull();
assertThat(methodGeneratorFactory.getBeanDefinitionMethodGenerator(registeredBean2, null)).isNull();
}
@Test
void getBeanDefinitionMethodGeneratorWhenRegisteredBeanIsAotProcessorAndFilteresBeanBeanRegistrationExcludeFilterDoesNotFilterBean() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder
.rootBeanDefinition(TestBeanRegistrationAotProcessorAndFilterBean.class).getBeanDefinition());
RegisteredBean registeredBean1 = RegisteredBean.of(beanFactory, "test");
BeanDefinitionMethodGeneratorFactory methodGeneratorFactory = new BeanDefinitionMethodGeneratorFactory(
new AotFactoriesLoader(beanFactory, springFactoriesLoader));
assertThat(methodGeneratorFactory.getBeanDefinitionMethodGenerator(registeredBean1, null)).isNotNull();
}
private RegisteredBean registerTestBean(DefaultListableBeanFactory beanFactory) {
beanFactory.registerBeanDefinition("test", BeanDefinitionBuilder
.rootBeanDefinition(TestBean.class).getBeanDefinition());
@ -150,6 +179,35 @@ class BeanDefinitionMethodGeneratorFactoryTests {
}
static class TestBeanFactoryInitializationAotProcessorBean implements BeanFactoryInitializationAotProcessor{
@Override
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
return null;
}
}
static class TestBeanRegistrationAotProcessorBean implements BeanRegistrationAotProcessor {
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
return null;
}
}
static class TestBeanRegistrationAotProcessorAndFilterBean
extends TestBeanRegistrationAotProcessorBean
implements BeanRegistrationExcludeFilter {
@Override
public boolean isExcluded(RegisteredBean registeredBean) {
return false;
}
}
static class InnerTestBean {
}