Skip to content

Commit 9a7a4a4

Browse files
committed
Don't cause early FactoryBean instantiation
Update ConfigurationPropertiesBindingPostProcessor to use `getBeansOfType` with `allowEagerInit=false` rather than `getBean`. This prevents FactoryBeans from being instantiated early when their type is not known. Fixed spring-projectsgh-1365
1 parent cac3865 commit 9a7a4a4

File tree

2 files changed

+78
-8
lines changed

2 files changed

+78
-8
lines changed

spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.util.Iterator;
21+
import java.util.Map;
2122

2223
import org.springframework.beans.BeansException;
2324
import org.springframework.beans.factory.BeanCreationException;
@@ -203,15 +204,10 @@ public void destroy() throws Exception {
203204
}
204205

205206
private PropertySources deducePropertySources() {
206-
try {
207-
PropertySourcesPlaceholderConfigurer configurer = this.beanFactory
208-
.getBean(PropertySourcesPlaceholderConfigurer.class);
209-
PropertySources propertySources = configurer.getAppliedPropertySources();
207+
PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();
208+
if (configurer != null) {
210209
// Flatten the sources into a single list so they can be iterated
211-
return new FlatPropertySources(propertySources);
212-
}
213-
catch (NoSuchBeanDefinitionException ex) {
214-
// Continue if no PropertySourcesPlaceholderConfigurer bean
210+
return new FlatPropertySources(configurer.getAppliedPropertySources());
215211
}
216212

217213
if (this.environment instanceof ConfigurableEnvironment) {
@@ -224,6 +220,20 @@ private PropertySources deducePropertySources() {
224220
return new MutablePropertySources();
225221
}
226222

223+
private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {
224+
// Take care not to cause early instantiation of all FactoryBeans
225+
if (this.beanFactory instanceof ListableBeanFactory) {
226+
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;
227+
Map<String, PropertySourcesPlaceholderConfigurer> beans = listableBeanFactory
228+
.getBeansOfType(PropertySourcesPlaceholderConfigurer.class, false,
229+
false);
230+
if (beans.size() == 1) {
231+
return beans.values().iterator().next();
232+
}
233+
}
234+
return null;
235+
}
236+
227237
private <T> T getOptionalBean(String name, Class<T> type) {
228238
try {
229239
return this.beanFactory.getBean(name, type);

spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@
2121

2222
import org.junit.After;
2323
import org.junit.Test;
24+
import org.springframework.beans.BeansException;
2425
import org.springframework.beans.factory.BeanCreationException;
26+
import org.springframework.beans.factory.FactoryBean;
27+
import org.springframework.beans.factory.InitializingBean;
2528
import org.springframework.beans.factory.annotation.Value;
29+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
30+
import org.springframework.beans.factory.support.GenericBeanDefinition;
2631
import org.springframework.boot.test.EnvironmentTestUtils;
2732
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2833
import org.springframework.context.annotation.Bean;
@@ -36,8 +41,10 @@
3641

3742
import static org.hamcrest.Matchers.equalTo;
3843
import static org.junit.Assert.assertEquals;
44+
import static org.junit.Assert.assertFalse;
3945
import static org.junit.Assert.assertNotNull;
4046
import static org.junit.Assert.assertThat;
47+
import static org.junit.Assert.assertTrue;
4148
import static org.junit.Assert.fail;
4249

4350
/**
@@ -141,6 +148,26 @@ public void testValueBindingForDefaults() throws Exception {
141148
equalTo("foo"));
142149
}
143150

151+
@Test
152+
public void configurationPropertiesWithFactoryBean() throws Exception {
153+
ConfigurationPropertiesWithFactoryBean.factoryBeanInit = false;
154+
this.context = new AnnotationConfigApplicationContext() {
155+
@Override
156+
protected void onRefresh() throws BeansException {
157+
assertFalse("Init too early",
158+
ConfigurationPropertiesWithFactoryBean.factoryBeanInit);
159+
super.onRefresh();
160+
}
161+
};
162+
this.context.register(ConfigurationPropertiesWithFactoryBean.class);
163+
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
164+
beanDefinition.setBeanClass(FactoryBeanTester.class);
165+
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
166+
this.context.registerBeanDefinition("test", beanDefinition);
167+
this.context.refresh();
168+
assertTrue("No init", ConfigurationPropertiesWithFactoryBean.factoryBeanInit);
169+
}
170+
144171
@Configuration
145172
@EnableConfigurationProperties
146173
public static class TestConfigurationWithValidatingSetter {
@@ -299,4 +326,37 @@ public static PropertySourcesPlaceholderConfigurer configurer() {
299326

300327
}
301328

329+
@Configuration
330+
@EnableConfigurationProperties
331+
public static class ConfigurationPropertiesWithFactoryBean {
332+
333+
public static boolean factoryBeanInit;
334+
335+
}
336+
337+
@SuppressWarnings("rawtypes")
338+
// Must be a raw type
339+
static class FactoryBeanTester implements FactoryBean, InitializingBean {
340+
341+
@Override
342+
public Object getObject() throws Exception {
343+
return Object.class;
344+
}
345+
346+
@Override
347+
public Class<?> getObjectType() {
348+
return null;
349+
}
350+
351+
@Override
352+
public boolean isSingleton() {
353+
return true;
354+
}
355+
356+
@Override
357+
public void afterPropertiesSet() throws Exception {
358+
ConfigurationPropertiesWithFactoryBean.factoryBeanInit = true;
359+
}
360+
361+
}
302362
}

0 commit comments

Comments
 (0)