GH-2522 polishing previous commit

This commit is contained in:
Oleg Zhurakousky
2022-10-05 17:00:59 +02:00
parent 42a43af4c2
commit a84a42188d
2 changed files with 11 additions and 155 deletions

View File

@@ -36,13 +36,10 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry;
import org.springframework.cloud.stream.config.ListenerContainerCustomizer;
import org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration.SpelConverter;
import org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration;
import org.springframework.cloud.stream.reflection.GenericsUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -56,7 +53,6 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.messaging.MessageChannel;
@@ -306,101 +302,16 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
.get(configurationName).getKey();
}
@SuppressWarnings("unused")
private ConfigurableApplicationContext initializeBinderContextBoot(String configurationName, Map<String, Object> binderProperties,
BinderType binderType, BinderConfiguration binderConfiguration) {
// Convert all properties to arguments, so that they receive maximum
// // precedence
ArrayList<String> args = new ArrayList<>();
for (Map.Entry<String, Object> property : binderProperties.entrySet()) {
args.add(
String.format("--%s=%s", property.getKey(), property.getValue()));
}
// Initialize the domain with a unique name based on the bootstrapping context
// setting
ConfigurableEnvironment environment = this.context != null
? this.context.getEnvironment() : null;
String defaultDomain = environment != null
? environment.getProperty("spring.jmx.default-domain") : "";
args.add("--spring.jmx.default-domain=" + defaultDomain + "binder."
+ configurationName);
SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(
binderType.getConfigurationClasses())
.bannerMode(Mode.OFF).logStartupInfo(false)
.web(WebApplicationType.NONE);
// If the environment is not customized and a main context is available, we
// will set the latter as parent.
// This ensures that the defaults and user-defined customizations (e.g. custom
// connection factory beans)
// are propagated to the binder context. If the environment is customized,
// then the binder context should
// not inherit any beans from the parent
boolean useApplicationContextAsParent = binderProperties.isEmpty()
&& this.context != null;
if (useApplicationContextAsParent) {
springApplicationBuilder.parent(this.context);
}
else {
this.customizeParentChildContextRelationship(springApplicationBuilder, this.context);
springApplicationBuilder.listeners(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (context != null) {
try {
context.publishEvent(event);
}
catch (Exception e) {
logger.warn("Failed to publish " + event, e);
}
}
}
});
}
// 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();
binderEnvironment.merge(environment);
// See ConfigurationPropertySources.ATTACHED_PROPERTY_SOURCE_NAME
binderEnvironment.getPropertySources().remove("configurationProperties");
/*
* Ensure that the web mode is set to NONE despite what the
* parent application context says.
* https://github.com/spring-cloud/spring-cloud-stream/issues/1708
*/
binderEnvironment.getPropertySources()
.addFirst(new MapPropertySource("defaultBinderFactoryProperties",
Collections.singletonMap("spring.main.web-application-type", "NONE")));
springApplicationBuilder.environment(binderEnvironment);
}
ConfigurableApplicationContext binderProducingContext = springApplicationBuilder
.run(args.toArray(new String[0]));
return binderProducingContext;
}
@SuppressWarnings("rawtypes")
private ConfigurableApplicationContext initializeBinderContextSimple(String configurationName, Map<String, Object> binderProperties,
BinderType binderType, BinderConfiguration binderConfiguration) {
//======= NEW CODE
AnnotationConfigApplicationContext binderProducingContext = new AnnotationConfigApplicationContext();
if (this.context != null) {
binderProducingContext.getBeanFactory().setConversionService(this.context.getBeanFactory().getConversionService());
}
List<Class> sourceClasses = new ArrayList<>();
sourceClasses.addAll(Arrays.asList(binderType.getConfigurationClasses()));
sourceClasses.addAll(Collections.singletonList(SpelExpressionConverterConfiguration.class));
if (binderProperties.containsKey("spring.main.sources")) {
String sources = (String) binderProperties.get("spring.main.sources");
if (StringUtils.hasText(sources)) {
@@ -429,26 +340,6 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
else if (this.context != null) {
this.propagateSharedBeans(binderProducingContext);
Map<String, ListenerContainerCustomizer> customizers = this.context.getBeansOfType(ListenerContainerCustomizer.class);
if (!CollectionUtils.isEmpty(customizers)) {
for (Entry<String, ListenerContainerCustomizer> customizerEntry : customizers.entrySet()) {
ListenerContainerCustomizer customizerWrapper = new ListenerContainerCustomizer() {
@SuppressWarnings("unchecked")
@Override
public void configure(Object container, String destinationName, String group) {
try {
customizerEntry.getValue().configure(container, destinationName, group);
}
catch (Exception e) {
logger.warn("Failed while applying ListenerContainerCustomizer. In situations when multiple "
+ "binders are used this is expected, since a particular customizer may not be applicable.");
}
}
};
((GenericApplicationContext) binderProducingContext).registerBean(customizerEntry.getKey(),
ListenerContainerCustomizer.class, () -> customizerWrapper);
}
}
binderProducingContext.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
@@ -523,48 +414,6 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl
}
}
/**
* Creates a bare minimum application context that can be initialized by AOT.
*
* @param configurationName binder configuration name
* @param binderProperties binder properties
* @param binderConfiguration binder configuration
* @return a binder child application context suitable for AOT initialization
>>>>>>> 80e1e37a3... GH-2522 Add support for propagating select beans across child AC
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void customizeParentChildContextRelationship(SpringApplicationBuilder applicationBuilder, ApplicationContext context) {
if (context != null) {
Map<String, ListenerContainerCustomizer> customizers = context.getBeansOfType(ListenerContainerCustomizer.class);
applicationBuilder.initializers(childContext -> {
if (!CollectionUtils.isEmpty(customizers)) {
for (Entry<String, ListenerContainerCustomizer> customizerEntry : customizers.entrySet()) {
ListenerContainerCustomizer customizerWrapper = new ListenerContainerCustomizer() {
@Override
public void configure(Object container, String destinationName, String group) {
try {
customizerEntry.getValue().configure(container, destinationName, group);
}
catch (Exception e) {
logger.warn("Failed while applying ListenerContainerCustomizer. In situations when multiple "
+ "binders are used this is expected, since a particular customizer may not be applicable"
+ "to a particular binder. Customizer: " + customizerEntry.getValue()
+ " Binder: " + childContext.getBean(AbstractMessageChannelBinder.class), e);
}
}
};
((GenericApplicationContext) childContext).registerBean(customizerEntry.getKey(),
ListenerContainerCustomizer.class, () -> customizerWrapper);
}
}
GenericConversionService cs = (GenericConversionService) ((GenericApplicationContext) childContext).getBeanFactory().getConversionService();
SpelConverter spelConverter = new SpelConverter();
cs.addConverter(spelConverter);
});
}
}
/**
* Ensures that nested properties are flattened (i.e., foo.bar=baz instead of
* foo={bar=baz}).

View File

@@ -22,11 +22,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
@@ -67,8 +69,13 @@ public class SpelExpressionConverterConfiguration {
@Bean
@ConfigurationPropertiesBinding
@IntegrationConverter
public Converter<String, Expression> spelConverter() {
return new SpelConverter();
public Converter<String, Expression> spelConverter(ConfigurableApplicationContext context) {
SpelConverter converter = new SpelConverter();
ConfigurableConversionService cs = (ConfigurableConversionService) context.getBeanFactory().getConversionService();
if (cs != null) {
cs.addConverter(converter);
}
return converter;
}
/**