Skip to content

Commit ebe3b37

Browse files
committed
Allow MergedBeanDefinitionPostProcessor to handle bean creation
This commit registers the MergedBeanDefinitionPostProcessor instances on the BeanFactory processed for AOT purposes. This allows beans that are created at build-time to be post-processed for low-level needs such as initialization and autowiring. Closes gh-28777
1 parent 9573fc9 commit ebe3b37

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ private static void invokeBeanFactoryPostProcessors(
364364
* Register the given BeanPostProcessor beans.
365365
*/
366366
private static void registerBeanPostProcessors(
367-
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
367+
ConfigurableListableBeanFactory beanFactory, List<? extends BeanPostProcessor> postProcessors) {
368368

369369
if (beanFactory instanceof AbstractBeanFactory) {
370370
// Bulk addition is more efficient against our CopyOnWriteArrayList there
@@ -439,6 +439,7 @@ private void invokeMergedBeanDefinitionPostProcessors() {
439439
Class<?> beanType = resolveBeanType(bd);
440440
postProcessRootBeanDefinition(postProcessors, beanName, beanType, bd);
441441
}
442+
registerBeanPostProcessors(this.beanFactory, postProcessors);
442443
}
443444

444445
private void postProcessRootBeanDefinition(List<MergedBeanDefinitionPostProcessor> postProcessors,

spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,24 @@ void refreshForAotProcessingWithConfiguration() {
431431
"annotationConfigApplicationContextTests.Config", "testBean");
432432
}
433433

434+
@Test
435+
void refreshForAotCanInstantiateBeanWithAutowiredApplicationContext() {
436+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
437+
context.register(BeanD.class);
438+
context.refreshForAotProcessing();
439+
BeanD bean = context.getBean(BeanD.class);
440+
assertThat(bean.applicationContext).isSameAs(context);
441+
}
442+
443+
@Test
444+
void refreshForAotCanInstantiateBeanWithFieldAutowiredApplicationContext() {
445+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
446+
context.register(BeanB.class);
447+
context.refreshForAotProcessing();
448+
BeanB bean = context.getBean(BeanB.class);
449+
assertThat(bean.applicationContext).isSameAs(context);
450+
}
451+
434452

435453
@Configuration
436454
static class Config {
@@ -506,6 +524,16 @@ public BeanB() {
506524

507525
static class BeanC {}
508526

527+
static class BeanD {
528+
529+
private final ApplicationContext applicationContext;
530+
531+
public BeanD(ApplicationContext applicationContext) {
532+
this.applicationContext = applicationContext;
533+
}
534+
535+
}
536+
509537
static class NonInstantiatedFactoryBean implements FactoryBean<String> {
510538

511539
NonInstantiatedFactoryBean() {

spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import org.junit.jupiter.api.condition.OS;
2424
import org.mockito.ArgumentCaptor;
2525

26+
import org.springframework.beans.BeansException;
2627
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
2728
import org.springframework.beans.factory.config.AbstractFactoryBean;
2829
import org.springframework.beans.factory.config.BeanDefinition;
2930
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
31+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3032
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3133
import org.springframework.beans.factory.support.GenericBeanDefinition;
3234
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
@@ -407,6 +409,32 @@ void refreshForAotInvokesMergedBeanDefinitionPostProcessorsOnPropertyValue() {
407409
context.close();
408410
}
409411

412+
@Test
413+
void refreshForAotInvokesBeanPostProcessorContractOnMergedBeanDefinitionPostProcessors() {
414+
MergedBeanDefinitionPostProcessor bpp = new MergedBeanDefinitionPostProcessor() {
415+
@Override
416+
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
417+
beanDefinition.setAttribute("mbdppCalled", true);
418+
}
419+
420+
@Override
421+
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
422+
return (beanName.equals("test") ? "42" : bean);
423+
}
424+
};
425+
GenericApplicationContext context = new GenericApplicationContext();
426+
context.registerBeanDefinition("bpp", BeanDefinitionBuilder.rootBeanDefinition(
427+
MergedBeanDefinitionPostProcessor.class, () -> bpp)
428+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
429+
AbstractBeanDefinition bd = BeanDefinitionBuilder.rootBeanDefinition(String.class)
430+
.addConstructorArgValue("value").getBeanDefinition();
431+
context.registerBeanDefinition("test", bd);
432+
context.refreshForAotProcessing();
433+
assertThat(context.getBeanFactory().getMergedBeanDefinition("test")
434+
.hasAttribute("mbdppCalled")).isTrue();
435+
assertThat(context.getBean("test")).isEqualTo("42");
436+
}
437+
410438
@Test
411439
void refreshForAotFailsOnAnActiveContext() {
412440
GenericApplicationContext context = new GenericApplicationContext();

0 commit comments

Comments
 (0)