From 6f71328ba6f8d2d6d001cf26f24459852ee5dd8f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 26 May 2022 20:59:50 -0700 Subject: [PATCH] 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 --- .../BeanDefinitionMethodGeneratorFactory.java | 3 + ...nFactoryInitializationAotContribution.java | 4 ++ ...BeanFactoryInitializationAotProcessor.java | 4 ++ ...DefinitionMethodGeneratorFactoryTests.java | 58 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java index f4b741394cb..c8961659b10 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactory.java @@ -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); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotContribution.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotContribution.java index 7d3b497e9de..2cfffc4a87b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotContribution.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotContribution.java @@ -22,6 +22,10 @@ import org.springframework.aot.generate.GenerationContext; * AOT contribution from a {@link BeanFactoryInitializationAotProcessor} used to * initialize a bean factory. * + *

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 diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotProcessor.java index 9765e2c1f58..f48a53e1453 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanFactoryInitializationAotProcessor.java @@ -23,6 +23,10 @@ import org.springframework.lang.Nullable; * AOT processor that makes bean factory initialization contributions by * processing {@link ConfigurableListableBeanFactory} instances. * + *

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 diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactoryTests.java index e238a8570ff..247216a7c51 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionMethodGeneratorFactoryTests.java @@ -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 { }