Skip to content

Commit 7838c7b

Browse files
committed
Polish 'Support ConfigurationClassPostProcessor supplier'
See gh-22858
1 parent 06eff45 commit 7838c7b

File tree

2 files changed

+96
-21
lines changed

2 files changed

+96
-21
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,10 +19,12 @@
1919
import java.util.function.Supplier;
2020

2121
import org.springframework.beans.BeansException;
22+
import org.springframework.beans.MutablePropertyValues;
2223
import org.springframework.beans.factory.BeanClassLoaderAware;
2324
import org.springframework.beans.factory.FactoryBean;
2425
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2526
import org.springframework.beans.factory.config.BeanDefinition;
27+
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
2628
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2729
import org.springframework.beans.factory.config.RuntimeBeanReference;
2830
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -47,6 +49,7 @@
4749
* {@link ConfigurationClassPostProcessor} and Spring Boot.
4850
*
4951
* @author Phillip Webb
52+
* @author Dave Syer
5053
*/
5154
class SharedMetadataReaderFactoryContextInitializer
5255
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
@@ -56,7 +59,8 @@ class SharedMetadataReaderFactoryContextInitializer
5659

5760
@Override
5861
public void initialize(ConfigurableApplicationContext applicationContext) {
59-
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor(applicationContext));
62+
BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);
63+
applicationContext.addBeanFactoryPostProcessor(postProcessor);
6064
}
6165

6266
@Override
@@ -69,7 +73,7 @@ public int getOrder() {
6973
* {@link CachingMetadataReaderFactory} and configure the
7074
* {@link ConfigurationClassPostProcessor}.
7175
*/
72-
private static class CachingMetadataReaderFactoryPostProcessor
76+
static class CachingMetadataReaderFactoryPostProcessor
7377
implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
7478

7579
private ConfigurableApplicationContext context;
@@ -103,28 +107,64 @@ private void register(BeanDefinitionRegistry registry) {
103107

104108
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
105109
try {
106-
BeanDefinition definition = registry
107-
.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
108-
if (definition instanceof AbstractBeanDefinition) {
109-
AbstractBeanDefinition bean = (AbstractBeanDefinition) definition;
110-
if (bean.getInstanceSupplier() != null) {
111-
Supplier<?> supplier = bean.getInstanceSupplier();
112-
bean.setInstanceSupplier(() -> modify(supplier));
113-
return;
114-
}
115-
}
116-
definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
110+
configureConfigurationClassPostProcessor(
111+
registry.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
117112
}
118113
catch (NoSuchBeanDefinitionException ex) {
119114
}
120115
}
121116

122-
private Object modify(Supplier<?> supplier) {
123-
Object object = supplier.get();
124-
if (object instanceof ConfigurationClassPostProcessor) {
125-
((ConfigurationClassPostProcessor) object).setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class));
117+
private void configureConfigurationClassPostProcessor(BeanDefinition definition) {
118+
if (definition instanceof AbstractBeanDefinition) {
119+
configureConfigurationClassPostProcessor((AbstractBeanDefinition) definition);
120+
return;
126121
}
127-
return object;
122+
configureConfigurationClassPostProcessor(definition.getPropertyValues());
123+
}
124+
125+
private void configureConfigurationClassPostProcessor(AbstractBeanDefinition definition) {
126+
Supplier<?> instanceSupplier = definition.getInstanceSupplier();
127+
if (instanceSupplier != null) {
128+
definition.setInstanceSupplier(
129+
new ConfigurationClassPostProcessorCustomizingSupplier(this.context, instanceSupplier));
130+
return;
131+
}
132+
configureConfigurationClassPostProcessor(definition.getPropertyValues());
133+
}
134+
135+
private void configureConfigurationClassPostProcessor(MutablePropertyValues propertyValues) {
136+
propertyValues.add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
137+
}
138+
139+
}
140+
141+
/**
142+
* {@link Supplier} used to customize the {@link ConfigurationClassPostProcessor} when
143+
* it's first created.
144+
*/
145+
static class ConfigurationClassPostProcessorCustomizingSupplier implements Supplier<Object> {
146+
147+
private final ConfigurableApplicationContext context;
148+
149+
private final Supplier<?> instanceSupplier;
150+
151+
ConfigurationClassPostProcessorCustomizingSupplier(ConfigurableApplicationContext context,
152+
Supplier<?> instanceSupplier) {
153+
this.context = context;
154+
this.instanceSupplier = instanceSupplier;
155+
}
156+
157+
@Override
158+
public Object get() {
159+
Object instance = this.instanceSupplier.get();
160+
if (instance instanceof ConfigurationClassPostProcessor) {
161+
configureConfigurationClassPostProcessor((ConfigurationClassPostProcessor) instance);
162+
}
163+
return instance;
164+
}
165+
166+
private void configureConfigurationClassPostProcessor(ConfigurationClassPostProcessor instance) {
167+
instance.setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class));
128168
}
129169

130170
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializerTests.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,32 +19,43 @@
1919
import java.util.List;
2020

2121
import org.junit.jupiter.api.Test;
22+
import org.mockito.ArgumentCaptor;
2223

2324
import org.springframework.beans.BeansException;
2425
import org.springframework.beans.factory.config.BeanDefinition;
2526
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
27+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
28+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2629
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2730
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
2831
import org.springframework.boot.SpringApplication;
2932
import org.springframework.boot.WebApplicationType;
33+
import org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor;
34+
import org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory;
3035
import org.springframework.context.ApplicationContextInitializer;
36+
import org.springframework.context.annotation.AnnotationConfigUtils;
37+
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
3138
import org.springframework.context.support.GenericApplicationContext;
39+
import org.springframework.core.type.classreading.MetadataReaderFactory;
3240
import org.springframework.test.util.ReflectionTestUtils;
3341

3442
import static org.assertj.core.api.Assertions.assertThat;
43+
import static org.mockito.Mockito.mock;
44+
import static org.mockito.Mockito.verify;
3545

3646
/**
3747
* Tests for {@link SharedMetadataReaderFactoryContextInitializer}.
3848
*
3949
* @author Dave Syer
50+
* @author Phillip Webb
4051
*/
4152
class SharedMetadataReaderFactoryContextInitializerTests {
4253

4354
@Test
55+
@SuppressWarnings("unchecked")
4456
void checkOrderOfInitializer() {
4557
SpringApplication application = new SpringApplication(TestConfig.class);
4658
application.setWebApplicationType(WebApplicationType.NONE);
47-
@SuppressWarnings("unchecked")
4859
List<ApplicationContextInitializer<?>> initializers = (List<ApplicationContextInitializer<?>>) ReflectionTestUtils
4960
.getField(application, "initializers");
5061
// Simulate what would happen if an initializer was added using spring.factories
@@ -55,6 +66,30 @@ void checkOrderOfInitializer() {
5566
assertThat(definition.getAttribute("seen")).isEqualTo(true);
5667
}
5768

69+
@Test
70+
void initializeWhenUsingSupplierDecorates() {
71+
GenericApplicationContext context = new GenericApplicationContext();
72+
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
73+
ConfigurationClassPostProcessor configurationAnnotationPostProcessor = mock(
74+
ConfigurationClassPostProcessor.class);
75+
BeanDefinition beanDefinition = BeanDefinitionBuilder
76+
.genericBeanDefinition(ConfigurationClassPostProcessor.class).getBeanDefinition();
77+
((AbstractBeanDefinition) beanDefinition).setInstanceSupplier(() -> configurationAnnotationPostProcessor);
78+
registry.registerBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,
79+
beanDefinition);
80+
CachingMetadataReaderFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(
81+
context);
82+
postProcessor.postProcessBeanDefinitionRegistry(registry);
83+
context.refresh();
84+
ConfigurationClassPostProcessor bean = context.getBean(ConfigurationClassPostProcessor.class);
85+
assertThat(bean).isSameAs(configurationAnnotationPostProcessor);
86+
ArgumentCaptor<MetadataReaderFactory> metadataReaderFactory = ArgumentCaptor
87+
.forClass(MetadataReaderFactory.class);
88+
verify(configurationAnnotationPostProcessor).setMetadataReaderFactory(metadataReaderFactory.capture());
89+
assertThat(metadataReaderFactory.getValue())
90+
.isInstanceOf(ConcurrentReferenceCachingMetadataReaderFactory.class);
91+
}
92+
5893
static class TestConfig {
5994

6095
}

0 commit comments

Comments
 (0)