diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactoryListener.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactoryListener.java deleted file mode 100644 index 00ae25ec5..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderFactoryListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder; - -import org.springframework.context.ConfigurableApplicationContext; - -/** - * This interface adds additional capabilities to the binder when it is created. - * - * @author Ilayaperumal Gopinathan - */ -public interface BinderFactoryListener { - - /** - * Applying additional capabilities to the binder when creating the new binder instance. - * @param configurationName the binder configuration name - * @param binderProducingContext the application context of the binder - */ - void apply(String configurationName, ConfigurableApplicationContext binderProducingContext); -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorAutoConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorAutoConfiguration.java deleted file mode 100644 index bfda3d513..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorAutoConfiguration.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator; -import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; -import org.springframework.boot.actuate.health.CompositeHealthIndicator; -import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Ilayaperumal Gopinathan - */ -@ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator") -@ConditionalOnEnabledHealthIndicator("binders") -@AutoConfigureBefore(EndpointAutoConfiguration.class) -@Configuration -public class BindersHealthIndicatorAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(name = "bindersHealthIndicator") - public CompositeHealthIndicator bindersHealthIndicator() { - return new CompositeHealthIndicator(new OrderedHealthAggregator()); - } - - @Bean - public BinderFactoryListener bindersHealthIndicatorListener(@Qualifier("bindersHealthIndicator") CompositeHealthIndicator compositeHealthIndicator) { - return new BindersHealthIndicatorListener(compositeHealthIndicator); - } -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorListener.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorListener.java deleted file mode 100644 index 86b646154..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BindersHealthIndicatorListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.stream.binder; - -import java.util.Map; - -import org.springframework.boot.actuate.health.AbstractHealthIndicator; -import org.springframework.boot.actuate.health.CompositeHealthIndicator; -import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.context.ConfigurableApplicationContext; - -/** - * {@link BinderFactoryListener} that provides {@link HealthIndicator} support. - * - * @author Ilayaperumal Gopinathan - */ -public class BindersHealthIndicatorListener implements BinderFactoryListener { - - private final CompositeHealthIndicator bindersHealthIndicator; - - public BindersHealthIndicatorListener(CompositeHealthIndicator bindersHealthIndicator) { - this.bindersHealthIndicator = bindersHealthIndicator; - } - - @Override - public void apply(String binderConfigurationName, ConfigurableApplicationContext binderProducingContext) { - if (this.bindersHealthIndicator != null) { - OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator(); - Map indicators = binderProducingContext.getBeansOfType(HealthIndicator.class); - // if there are no health indicators in the child context, we just mark the binder's health as unknown - // this can happen due to the fact that configuration is inherited - HealthIndicator binderHealthIndicator = - indicators.isEmpty() ? new DefaultHealthIndicator() : new CompositeHealthIndicator( - healthAggregator, indicators); - this.bindersHealthIndicator.addHealthIndicator(binderConfigurationName, binderHealthIndicator); - } - } - - private static class DefaultHealthIndicator extends AbstractHealthIndicator { - - @Override - protected void doHealthCheck(Health.Builder builder) throws Exception { - builder.unknown(); - } - } -} - diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java index cf6cd2fc6..ffd34065f 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java @@ -55,7 +55,7 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl private Map defaultBinderForBindingTargetType = new HashMap<>(); - private Collection binderFactoryListeners; + private Collection listeners; private volatile String defaultBinder; @@ -73,8 +73,8 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl this.defaultBinder = defaultBinder; } - public void setBinderFactoryListeners(Collection binderFactoryListeners) { - this.binderFactoryListeners = binderFactoryListeners; + public void setListeners(Collection listeners) { + this.listeners = listeners; } @Override @@ -112,7 +112,8 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl List candidatesForBindableType = new ArrayList<>(); for (String defaultCandidateConfiguration : defaultCandidateConfigurations) { Binder binderInstance = getBinderInstance(defaultCandidateConfiguration); - Class binderType = GenericsUtils.getParameterType(binderInstance.getClass(), Binder.class, 0); + Class binderType = GenericsUtils.getParameterType(binderInstance.getClass(), + Binder.class, 0); if (binderType.isAssignableFrom(bindingTargetType)) { candidatesForBindableType.add(defaultCandidateConfiguration); } @@ -129,8 +130,8 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl + ", and no default binder has been set."); } else { - throw new IllegalStateException("A default binder has been requested, but none of the " + - "registered binders can bind a '" + bindingTargetType + "': " + throw new IllegalStateException("A default binder has been requested, but none of the " + + "registered binders can bind a '" + bindingTargetType + "': " + StringUtils.collectionToCommaDelimitedString(defaultCandidateConfigurations)); } } @@ -163,12 +164,14 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl throw new IllegalStateException("Unknown binder configuration: " + configurationName); } Properties binderProperties = binderConfiguration.getProperties(); - // Convert all properties to arguments, so that they receive maximum precedence + // Convert all properties to arguments, so that they receive maximum + // precedence ArrayList args = new ArrayList<>(); for (Map.Entry 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 + // 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") : null; if (defaultDomain == null) { @@ -179,17 +182,16 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl } args.add("--spring.jmx.default-domain=" + defaultDomain + "binder." + configurationName); args.add("--spring.main.applicationContextClass=" + AnnotationConfigApplicationContext.class.getName()); - List> configurationClasses = - new ArrayList>( - Arrays.asList(binderConfiguration.getBinderType().getConfigurationClasses())); - SpringApplicationBuilder springApplicationBuilder = - new SpringApplicationBuilder() - .sources(configurationClasses.toArray(new Class[]{})) - .bannerMode(Mode.OFF) - .web(false); - // 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 + List> configurationClasses = new ArrayList>( + Arrays.asList(binderConfiguration.getBinderType().getConfigurationClasses())); + SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder() + .sources(configurationClasses.toArray(new Class[] {})).bannerMode(Mode.OFF).web(false); + // 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) { @@ -202,23 +204,23 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl springApplicationBuilder.environment(binderEnvironment); } } - ConfigurableApplicationContext binderProducingContext = - springApplicationBuilder.run(args.toArray(new String[args.size()])); + ConfigurableApplicationContext binderProducingContext = springApplicationBuilder + .run(args.toArray(new String[args.size()])); @SuppressWarnings("unchecked") Binder binder = binderProducingContext.getBean(Binder.class); - if (this.binderFactoryListeners != null) { - for (BinderFactoryListener binderFactoryListener : binderFactoryListeners) { - binderFactoryListener.apply(configurationName, binderProducingContext); + if (this.listeners != null) { + for (Listener binderFactoryListener : listeners) { + binderFactoryListener.afterBinderContextInitialized(configurationName, binderProducingContext); } } - this.binderInstanceCache.put(configurationName, new BinderInstanceHolder(binder, - binderProducingContext)); + this.binderInstanceCache.put(configurationName, new BinderInstanceHolder(binder, binderProducingContext)); } return (Binder) this.binderInstanceCache.get(configurationName).getBinderInstance(); } /** - * Utility class for storing {@link Binder} instances, along with their associated contexts. + * Utility class for storing {@link Binder} instances, along with their associated + * contexts. */ private static final class BinderInstanceHolder { @@ -239,4 +241,23 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl return this.binderContext; } } + + /** + * A listener that can be registered with the {@link DefaultBinderFactory} that + * allows the registration of additional configuration. + * + * @author Ilayaperumal Gopinathan + */ + public interface Listener { + + /** + * Applying additional capabilities to the binder after the binder context + * has been initialized. + * + * @param configurationName the binder configuration name + * @param binderContext the application context of the binder + */ + void afterBinderContextInitialized(String configurationName, + ConfigurableApplicationContext binderContext); + } } diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BinderFactoryConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BinderFactoryConfiguration.java index 91a2dc291..8674b8c97 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BinderFactoryConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BinderFactoryConfiguration.java @@ -33,7 +33,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.stream.binder.BinderConfiguration; import org.springframework.cloud.stream.binder.BinderFactory; -import org.springframework.cloud.stream.binder.BinderFactoryListener; import org.springframework.cloud.stream.binder.BinderType; import org.springframework.cloud.stream.binder.BinderTypeRegistry; import org.springframework.cloud.stream.binder.DefaultBinderFactory; @@ -71,14 +70,14 @@ public class BinderFactoryConfiguration { private BindingServiceProperties bindingServiceProperties; @Autowired(required = false) - private Collection binderFactoryListeners; + private Collection binderFactoryListeners; @Bean @ConditionalOnMissingBean(BinderFactory.class) - public BinderFactory binderFactory() { + public DefaultBinderFactory binderFactory() { DefaultBinderFactory binderFactory = new DefaultBinderFactory(getBinderConfigurations()); binderFactory.setDefaultBinder(bindingServiceProperties.getDefaultBinder()); - binderFactory.setBinderFactoryListeners(binderFactoryListeners); + binderFactory.setListeners(binderFactoryListeners); return binderFactory; } diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindersHealthIndicatorAutoConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindersHealthIndicatorAutoConfiguration.java new file mode 100644 index 000000000..e0ecdf387 --- /dev/null +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindersHealthIndicatorAutoConfiguration.java @@ -0,0 +1,95 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.stream.config; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.OrderedHealthAggregator; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.stream.binder.DefaultBinderFactory; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Ilayaperumal Gopinathan + */ +@ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator") +@ConditionalOnEnabledHealthIndicator("binders") +@AutoConfigureBefore(EndpointAutoConfiguration.class) +@ConditionalOnBean(DefaultBinderFactory.class) +@Configuration +public class BindersHealthIndicatorAutoConfiguration { + + @Bean + @ConditionalOnMissingBean(name = "bindersHealthIndicator") + public CompositeHealthIndicator bindersHealthIndicator() { + return new CompositeHealthIndicator(new OrderedHealthAggregator()); + } + + @Bean + public DefaultBinderFactory.Listener bindersHealthIndicatorListener( + @Qualifier("bindersHealthIndicator") CompositeHealthIndicator compositeHealthIndicator) { + return new BindersHealthIndicatorListener(compositeHealthIndicator); + } + + /** + * A {@link DefaultBinderFactory.Listener} that provides {@link HealthIndicator} support. + * + * @author Ilayaperumal Gopinathan + */ + private static class BindersHealthIndicatorListener implements DefaultBinderFactory.Listener { + + private final CompositeHealthIndicator bindersHealthIndicator; + + BindersHealthIndicatorListener(CompositeHealthIndicator bindersHealthIndicator) { + this.bindersHealthIndicator = bindersHealthIndicator; + } + + @Override + public void afterBinderContextInitialized(String binderConfigurationName, ConfigurableApplicationContext binderContext) { + if (this.bindersHealthIndicator != null) { + OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator(); + Map indicators = binderContext.getBeansOfType(HealthIndicator.class); + // if there are no health indicators in the child context, we just mark + // the binder's health as unknown + // this can happen due to the fact that configuration is inherited + HealthIndicator binderHealthIndicator = indicators.isEmpty() ? new DefaultHealthIndicator() + : new CompositeHealthIndicator(healthAggregator, indicators); + this.bindersHealthIndicator.addHealthIndicator(binderConfigurationName, binderHealthIndicator); + } + } + + private static class DefaultHealthIndicator extends AbstractHealthIndicator { + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + builder.unknown(); + } + } + } +} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelBindingAutoConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelBindingAutoConfiguration.java index 8398c1591..17a4af0c0 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelBindingAutoConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelBindingAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cloud.stream.binding.BindingService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.integration.scheduling.PollerMetadata; import org.springframework.messaging.MessageChannel; @@ -38,7 +37,6 @@ import org.springframework.messaging.MessageChannel; @Configuration @ConditionalOnBean(BindingService.class) @EnableConfigurationProperties(DefaultPollerProperties.class) -@Import(ChannelsEndpointConfiguration.class) public class ChannelBindingAutoConfiguration { @Autowired diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointAutoConfiguration.java similarity index 87% rename from spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointConfiguration.java rename to spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointAutoConfiguration.java index 6b8349ad3..15d536f83 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/ChannelsEndpointAutoConfiguration.java @@ -21,8 +21,10 @@ import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.cloud.stream.binding.Bindable; +import org.springframework.cloud.stream.binding.BindingService; import org.springframework.cloud.stream.endpoint.ChannelsEndpoint; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,8 +36,9 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @ConditionalOnClass(name = "org.springframework.boot.actuate.endpoint.Endpoint") +@ConditionalOnBean(BindingService.class) @AutoConfigureAfter(EndpointAutoConfiguration.class) -public class ChannelsEndpointConfiguration { +public class ChannelsEndpointAutoConfiguration { @Autowired(required = false) private List adapters; diff --git a/spring-cloud-stream/src/main/resources/META-INF/spring.factories b/spring-cloud-stream/src/main/resources/META-INF/spring.factories index 999c33304..8a18c68f6 100644 --- a/spring-cloud-stream/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-stream/src/main/resources/META-INF/spring.factories @@ -1,3 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration:\ org.springframework.cloud.stream.config.ChannelBindingAutoConfiguration,\ - org.springframework.cloud.stream.binder.BindersHealthIndicatorAutoConfiguration +org.springframework.cloud.stream.config.BindersHealthIndicatorAutoConfiguration,\ +org.springframework.cloud.stream.config.ChannelsEndpointAutoConfiguration +