Properties propagation in custom environment
Currently when the binder configuration provide properties in a custom environment, Spring Cloud Stream does not include any beans from the outer context. This change will ensure that in such cases, the binder context will have access to the outer context as a non-parent bean. Resolves #1420 Resolves #1423
This commit is contained in:
committed by
Oleg Zhurakousky
parent
3bfe1775af
commit
daccfb5e58
@@ -35,6 +35,7 @@ import org.springframework.cloud.stream.config.SpelExpressionConverterConfigurat
|
||||
import org.springframework.cloud.stream.reflection.GenericsUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -50,6 +51,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Ilayaperumal Gopinathan
|
||||
* @author Gary Russell
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
public class DefaultBinderFactory implements BinderFactory, DisposableBean, ApplicationContextAware {
|
||||
|
||||
@@ -88,8 +90,8 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
this.binderInstanceCache.values().stream().map(e -> e.getValue()).forEach(ctx -> ctx.close());
|
||||
public void destroy() {
|
||||
this.binderInstanceCache.values().stream().map(Entry::getValue).forEach(ConfigurableApplicationContext::close);
|
||||
this.defaultBinderForBindingTargetType.clear();
|
||||
}
|
||||
|
||||
@@ -229,6 +231,11 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
|
||||
if (useApplicationContextAsParent) {
|
||||
springApplicationBuilder.parent(this.context);
|
||||
}
|
||||
// If the current application context is not set as parent and the environment is set,
|
||||
// provide the current context as an additional bean in the BeanFactory.
|
||||
if (environment != null && !useApplicationContextAsParent){
|
||||
springApplicationBuilder.initializers(new InitializerWithOuterContext(this.context));
|
||||
}
|
||||
|
||||
if (environment != null && (useApplicationContextAsParent || binderConfiguration.isInheritEnvironment())) {
|
||||
StandardEnvironment binderEnvironment = new StandardEnvironment();
|
||||
@@ -288,4 +295,18 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
|
||||
void afterBinderContextInitialized(String configurationName,
|
||||
ConfigurableApplicationContext binderContext);
|
||||
}
|
||||
|
||||
private static class InitializerWithOuterContext implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
private final ApplicationContext context;
|
||||
|
||||
InitializerWithOuterContext(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
applicationContext.getBeanFactory().registerSingleton("outerContext", context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import static org.junit.Assert.fail;
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
* @author Ilayaperumal Gopinathan
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
public class BinderFactoryConfigurationTests {
|
||||
|
||||
@@ -138,6 +139,37 @@ public class BinderFactoryConfigurationTests {
|
||||
assertThat(binderFactory.getBinder(null, MessageChannel.class)).isSameAs(binder1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testCustomEnvironmentHasAccessToOuterContext() throws Exception {
|
||||
ConfigurableApplicationContext context = createBinderTestContext(
|
||||
new String[] { "binder1" }, "binder1.name=foo",
|
||||
"spring.cloud.stream.binders.custom.environment.foo=bar",
|
||||
"spring.cloud.stream.binders.custom.type=binder1");
|
||||
|
||||
BinderFactory binderFactory = context.getBean(BinderFactory.class);
|
||||
|
||||
Binder binder1 = binderFactory.getBinder("custom", MessageChannel.class);
|
||||
|
||||
assertThat(binder1).hasFieldOrPropertyWithValue("name", "foo");
|
||||
assertThat(binder1).hasFieldOrPropertyWithValue("outerContext", context);
|
||||
|
||||
assertThat(binderFactory.getBinder(null, MessageChannel.class)).isSameAs(binder1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void testStandardBinderDoesNotHaveTheOuterContextBean() throws Exception {
|
||||
ConfigurableApplicationContext context = createBinderTestContext(
|
||||
new String[] { "binder1" }, "binder1.name=foo");
|
||||
|
||||
BinderFactory binderFactory = context.getBean(BinderFactory.class);
|
||||
Binder binder1 = binderFactory.getBinder("binder1", MessageChannel.class);
|
||||
assertThat(binder1).hasFieldOrPropertyWithValue("name", "foo");
|
||||
|
||||
assertThat(((StubBinder1) binder1).getOuterContext()).isNull();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void loadBinderTypeRegistryWithTwoBinders() throws Exception {
|
||||
|
||||
@@ -20,15 +20,27 @@ import org.springframework.cloud.stream.binder.Binder;
|
||||
import org.springframework.cloud.stream.binder.Binding;
|
||||
import org.springframework.cloud.stream.binder.ConsumerProperties;
|
||||
import org.springframework.cloud.stream.binder.ProducerProperties;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
* @author Mark Fisher
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
public class StubBinder1 implements Binder<Object, ConsumerProperties, ProducerProperties> {
|
||||
|
||||
private String name;
|
||||
|
||||
private ConfigurableApplicationContext outerContext;
|
||||
|
||||
public ConfigurableApplicationContext getOuterContext() {
|
||||
return outerContext;
|
||||
}
|
||||
|
||||
public void setOuterContext(ConfigurableApplicationContext outerContext) {
|
||||
this.outerContext = outerContext;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@@ -16,16 +16,20 @@
|
||||
|
||||
package org.springframework.cloud.stream.binder.stub1;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.stream.binder.Binder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
@@ -33,8 +37,19 @@ public class StubBinder1Configuration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("binder1")
|
||||
public Binder<?, ?, ?> binder() {
|
||||
return new StubBinder1();
|
||||
public Binder<?, ?, ?> binder(BeanFactory beanFactory) {
|
||||
StubBinder1 stubBinder1 = new StubBinder1();
|
||||
ConfigurableApplicationContext outerContext = null;
|
||||
try {
|
||||
outerContext = (ConfigurableApplicationContext) beanFactory.getBean("outerContext");
|
||||
}
|
||||
catch (BeansException be) {
|
||||
//Pass through
|
||||
}
|
||||
if (outerContext != null) {
|
||||
stubBinder1.setOuterContext(outerContext);
|
||||
}
|
||||
return stubBinder1;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
Reference in New Issue
Block a user