From 810803859aed515cf6a08f42b85cd822a509c203 Mon Sep 17 00:00:00 2001 From: Marius Bogoevici Date: Wed, 21 Sep 2016 02:39:42 -0400 Subject: [PATCH] Expose channel metrics for aggregate applications Fixes #660 #661 * Fix an issue where aggregated applications were not enabling web endpoints * Add spring-integration-jmx as mandatory dependency, so that SCSt applications expose metrics by default; * Remove `AggregatorParentConfiguration` as redundant * Register a `PublicMetrics` instance for each aggregate, using a customized version of SpringIntegrationMetricReader --- spring-cloud-stream/pom.xml | 4 + .../aggregate/AggregateApplication.java | 37 +++---- .../AggregateApplicationBuilder.java | 70 ++++++++++-- .../AggregatorParentConfiguration.java | 38 ------- ...aceAwareSpringIntegrationMetricReader.java | 104 ++++++++++++++++++ .../aggregate/SharedChannelRegistry.java | 4 +- .../aggregation/ModuleAggregationTest.java | 32 +++--- .../BinderFactoryConfigurationTests.java | 5 +- .../HealthIndicatorsConfigurationTests.java | 2 + .../binder/InputOutputBindingOrderTest.java | 1 + .../stream/binder/LifecycleBinderTests.java | 2 +- 11 files changed, 202 insertions(+), 97 deletions(-) delete mode 100644 spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregatorParentConfiguration.java create mode 100644 spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/NamespaceAwareSpringIntegrationMetricReader.java diff --git a/spring-cloud-stream/pom.xml b/spring-cloud-stream/pom.xml index 73a11c2ea..f4637e97b 100644 --- a/spring-cloud-stream/pom.xml +++ b/spring-cloud-stream/pom.xml @@ -34,6 +34,10 @@ org.springframework.integration spring-integration-core + + org.springframework.integration + spring-integration-jmx + org.springframework spring-tuple diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplication.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplication.java index 0927a78bd..e56e42e39 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplication.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplication.java @@ -27,6 +27,7 @@ import org.springframework.messaging.SubscribableChannel; /** * Class that is responsible for embedding apps using shared channel registry. + * * @author Marius Bogoevici * @author Ilayaperumal Gopinathan * @author Venil Noronha @@ -35,45 +36,35 @@ abstract class AggregateApplication { private static final String SPRING_CLOUD_STREAM_INTERNAL_PREFIX = "spring.cloud.stream.internal"; - private static final String CHANNEL_NAMESPACE_PROPERTY_NAME = SPRING_CLOUD_STREAM_INTERNAL_PREFIX + ".channelNamespace"; + private static final String CHANNEL_NAMESPACE_PROPERTY_NAME = + SPRING_CLOUD_STREAM_INTERNAL_PREFIX + ".channelNamespace"; - private static final String SELF_CONTAINED_APP_PROPERTY_NAME = SPRING_CLOUD_STREAM_INTERNAL_PREFIX + ".selfContained"; + private static final String SELF_CONTAINED_APP_PROPERTY_NAME = + SPRING_CLOUD_STREAM_INTERNAL_PREFIX + ".selfContained"; public static final String INPUT_CHANNEL_NAME = "input"; public static final String OUTPUT_CHANNEL_NAME = "output"; - static ConfigurableApplicationContext createParentContext(Object[] sources, String[] args, boolean selfContained) { + static ConfigurableApplicationContext createParentContext(Object[] sources, String[] args, final + boolean selfContained, boolean webEnvironment, + boolean headless) { SpringApplicationBuilder aggregatorParentConfiguration = new SpringApplicationBuilder(); aggregatorParentConfiguration - .sources(AggregatorParentConfiguration.class) .sources(sources) - .web(false) - .headless(true) + .web(webEnvironment) + .headless(headless) .properties("spring.jmx.default-domain=" - + AggregatorParentConfiguration.class.getName(), + + AggregateApplicationBuilder.ParentConfiguration.class.getName(), SELF_CONTAINED_APP_PROPERTY_NAME + "=" + selfContained); return aggregatorParentConfiguration.run(args); } - static ConfigurableApplicationContext createParentContext(ConfigurableApplicationContext parentContext, String[] args, - boolean selfContained) { - SpringApplicationBuilder aggregatorParentConfiguration = new SpringApplicationBuilder(); - aggregatorParentConfiguration - .sources(AggregatorParentConfiguration.class) - .web(false) - .headless(true) - .properties("spring.jmx.default-domain=" - + AggregatorParentConfiguration.class.getName(), - SELF_CONTAINED_APP_PROPERTY_NAME + "=" + selfContained) - .parent(parentContext); - return aggregatorParentConfiguration.run(args); - } - - static String getNamespace(String appClassName, int index) { + static String getDefaultNamespace(String appClassName, int index) { return appClassName + "_" + index; } + protected static SpringApplicationBuilder embedApp( ConfigurableApplicationContext parentContext, String namespace, Class app) { @@ -81,7 +72,7 @@ abstract class AggregateApplication { .web(false) .main(app) .bannerMode(Mode.OFF) - .properties("spring.jmx.default-domain=" + app) + .properties("spring.jmx.default-domain=" + namespace) .properties(CHANNEL_NAMESPACE_PROPERTY_NAME + "=" + namespace) .registerShutdownHook(false) .parent(parentContext); diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplicationBuilder.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplicationBuilder.java index 8e6e82782..09ea7047d 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplicationBuilder.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregateApplicationBuilder.java @@ -21,9 +21,15 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; +import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics; +import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.util.StringUtils; /** @@ -50,12 +56,16 @@ public class AggregateApplicationBuilder { private List parentArgs = new ArrayList<>(); + private boolean headless = true; + + private boolean webEnvironment = true; + public AggregateApplicationBuilder(String... args) { - this(new Object[]{ParentConfiguration.class}, args); + this(new Object[]{ ParentConfiguration.class }, args); } public AggregateApplicationBuilder(Object source, String... args) { - this(new Object[]{source}, args); + this(new Object[]{ source }, args); } public AggregateApplicationBuilder(Object[] sources, String[] args) { @@ -75,7 +85,7 @@ public class AggregateApplicationBuilder { } public AggregateApplicationBuilder parent(Object source, String... args) { - return parent(new Object[]{source}, args); + return parent(new Object[]{ source }, args); } public AggregateApplicationBuilder parent(Object[] sources, String[] args) { @@ -84,6 +94,30 @@ public class AggregateApplicationBuilder { return this; } + /** + * Flag to explicitly request a web or non-web environment. + * + * @param webEnvironment true if the application has a web environment + * @return the AggregateApplicationBuilder being constructed + * @see SpringApplicationBuilder#web(boolean) + */ + public AggregateApplicationBuilder web(boolean webEnvironment) { + this.webEnvironment = webEnvironment; + return this; + } + + /** + * Configures the headless attribute of the build application. + * + * @param headless true if the application is headless + * @return the AggregateApplicationBuilder being constructed + * @see SpringApplicationBuilder#headless(boolean) + */ + public AggregateApplicationBuilder headless(boolean headless) { + this.headless = headless; + return this; + } + public SourceConfigurer from(Class app) { SourceConfigurer sourceConfigurer = new SourceConfigurer(app); this.sourceConfigurer = sourceConfigurer; @@ -110,12 +144,13 @@ public class AggregateApplicationBuilder { Class appToEmbed = appConfigurer.getApp(); // Always update namespace before preparing SharedChannelRegistry if (appConfigurer.namespace == null) { - appConfigurer.namespace = AggregateApplication.getNamespace(appConfigurer.getApp().getName(), i); + appConfigurer.namespace = AggregateApplication.getDefaultNamespace(appConfigurer.getApp().getName(), + i); } appsToEmbed.put(appToEmbed, appConfigurer.namespace); } this.parentContext = AggregateApplication.createParentContext(this.parentSources.toArray(new Object[0]), - this.parentArgs.toArray(new String[0]), areAppsSelfContained()); + this.parentArgs.toArray(new String[0]), selfContained(), this.webEnvironment, this.headless); SharedChannelRegistry sharedChannelRegistry = this.parentContext.getBean(SharedChannelRegistry.class); AggregateApplication.prepareSharedChannelRegistry(sharedChannelRegistry, appsToEmbed); for (int i = apps.size() - 1; i >= 0; i--) { @@ -125,7 +160,7 @@ public class AggregateApplicationBuilder { return this.parentContext; } - private boolean areAppsSelfContained() { + private boolean selfContained() { return (this.sourceConfigurer != null) && (this.sinkConfigurer != null); } @@ -225,9 +260,15 @@ public class AggregateApplicationBuilder { } void embed() { - childContext(this.app, AggregateApplicationBuilder.this.parentContext, - this.namespace).args(this.args).config(this.names) - .profiles(this.profiles).run(); + final ConfigurableApplicationContext childContext = + childContext(this.app, AggregateApplicationBuilder.this.parentContext, + this.namespace).args(this.args).config(this.names) + .profiles(this.profiles).run(); + AggregateApplicationBuilder.this.parentContext.getBeanFactory().getBean( + MetricsEndpoint.class).registerPublicMetrics( + new MetricReaderPublicMetrics( + new NamespaceAwareSpringIntegrationMetricReader(this.namespace, childContext.getBean( + IntegrationMBeanExporter.class)))); } } @@ -262,7 +303,7 @@ public class AggregateApplicationBuilder { return this; } - public void run() { + public ConfigurableApplicationContext run() { List args = new ArrayList(); if (this.args != null) { args.addAll(Arrays.asList(this.args)); @@ -270,13 +311,18 @@ public class AggregateApplicationBuilder { if (this.configName != null) { args.add("--spring.config.name=" + this.configName); } - this.builder.run(args.toArray(new String[0])); + return this.builder.run(args.toArray(new String[0])); } } @EnableAutoConfiguration + @EnableBinding public static class ParentConfiguration { + @Bean + @ConditionalOnMissingBean(SharedChannelRegistry.class) + public SharedChannelRegistry sharedChannelRegistry() { + return new SharedChannelRegistry(); + } } - } diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregatorParentConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregatorParentConfiguration.java deleted file mode 100644 index 268cb17dd..000000000 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/AggregatorParentConfiguration.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015-2016 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.aggregate; - -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.cloud.stream.annotation.EnableBinding; -import org.springframework.context.annotation.Bean; - -/** - * Basic configuration for an aggregator application parent. - * - * @author Marius Bogoevici - */ -@EnableAutoConfiguration -@EnableBinding -public class AggregatorParentConfiguration { - - @Bean - @ConditionalOnMissingBean(SharedChannelRegistry.class) - public SharedChannelRegistry sharedChannelRegistry() { - return new SharedChannelRegistry(); - } -} diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/NamespaceAwareSpringIntegrationMetricReader.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/NamespaceAwareSpringIntegrationMetricReader.java new file mode 100644 index 000000000..2982c3b9f --- /dev/null +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/NamespaceAwareSpringIntegrationMetricReader.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016 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.aggregate; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.boot.actuate.metrics.Metric; +import org.springframework.boot.actuate.metrics.reader.MetricReader; +import org.springframework.integration.monitor.IntegrationMBeanExporter; +import org.springframework.integration.support.management.Statistics; +import org.springframework.util.Assert; + +/** + * A customized version of {@link org.springframework.boot.actuate.metrics.integration.SpringIntegrationMetricReader} that + * provides support for customizing channels with a namespace prefix. + * + * @author Marius Bogoevici + * @see org.springframework.boot.actuate.metrics.integration.SpringIntegrationMetricReader for original implementation + */ +public class NamespaceAwareSpringIntegrationMetricReader implements MetricReader { + + private final String namespace; + + private final IntegrationMBeanExporter exporter; + + public NamespaceAwareSpringIntegrationMetricReader(String namespace, IntegrationMBeanExporter exporter) { + Assert.hasText(namespace, "cannot be null or empty String"); + Assert.notNull(exporter, "cannot be null"); + this.namespace = namespace; + this.exporter = exporter; + } + + @Override + public Metric findOne(String metricName) { + return null; + } + + @Override + public Iterable> findAll() { + IntegrationMBeanExporter exporter = this.exporter; + List> metrics = new ArrayList>(); + for (String name : exporter.getChannelNames()) { + String prefix = "integration.channel." + namespace + "." + name; + metrics.addAll(getStatistics(prefix + ".errorRate", + exporter.getChannelErrorRate(name))); + metrics.add(new Metric(prefix + ".sendCount", + exporter.getChannelSendCountLong(name))); + metrics.addAll(getStatistics(prefix + ".sendRate", + exporter.getChannelSendRate(name))); + metrics.add(new Metric(prefix + ".receiveCount", + exporter.getChannelReceiveCountLong(name))); + } + for (String name : exporter.getHandlerNames()) { + metrics.addAll(getStatistics("integration." + namespace + ".handler." + name + ".duration", + exporter.getHandlerDuration(name))); + } + metrics.add(new Metric("integration." + namespace + ".activeHandlerCount", + exporter.getActiveHandlerCount())); + metrics.add(new Metric("integration." + namespace + ".handlerCount", + exporter.getHandlerCount())); + metrics.add(new Metric("integration." + namespace + ".channelCount", + exporter.getChannelCount())); + metrics.add(new Metric("integration." + namespace + ".queuedMessageCount", + exporter.getQueuedMessageCount())); + return metrics; + } + + private Collection> getStatistics(String name, + Statistics statistic) { + List> metrics = new ArrayList>(); + metrics.add(new Metric(name + ".mean", statistic.getMean())); + metrics.add(new Metric(name + ".max", statistic.getMax())); + metrics.add(new Metric(name + ".min", statistic.getMin())); + metrics.add( + new Metric(name + ".stdev", statistic.getStandardDeviation())); + metrics.add(new Metric(name + ".count", statistic.getCountLong())); + return metrics; + } + + @Override + public long count() { + int totalChannelCount = this.exporter.getChannelCount() * 11; + int totalHandlerCount = this.exporter.getHandlerCount() * 5; + return totalChannelCount + totalHandlerCount + 4; + } + +} + diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/SharedChannelRegistry.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/SharedChannelRegistry.java index 210b43f91..2dc52ae00 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/SharedChannelRegistry.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/aggregate/SharedChannelRegistry.java @@ -38,10 +38,10 @@ public class SharedChannelRegistry { } public void register(String id, MessageChannel messageChannel) { - sharedChannels.put(id, messageChannel); + this.sharedChannels.put(id, messageChannel); } public Map getAll() { - return Collections.unmodifiableMap(sharedChannels); + return Collections.unmodifiableMap(this.sharedChannels); } } diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/aggregation/ModuleAggregationTest.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/aggregation/ModuleAggregationTest.java index adf3755b7..8164f62f9 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/aggregation/ModuleAggregationTest.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/aggregation/ModuleAggregationTest.java @@ -16,13 +16,12 @@ package org.springframework.cloud.stream.aggregation; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import org.junit.Assert; import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.stream.aggregate.AggregateApplicationBuilder; import org.springframework.cloud.stream.aggregate.SharedChannelRegistry; @@ -34,7 +33,6 @@ import org.springframework.cloud.stream.utils.MockBinderRegistryConfiguration; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.MessageChannel; -import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -65,24 +63,22 @@ public class ModuleAggregationTest { argsToVerify.add("--foo1=bar1"); argsToVerify.add("--foo2=bar2"); argsToVerify.add("--foo3=bar3"); + argsToVerify.add("--server.port=0"); AggregateApplicationBuilder aggregateApplicationBuilder = new AggregateApplicationBuilder(MockBinderRegistryConfiguration.class, "--foo1=bar1"); - aggregateApplicationBuilder.parent(DummyConfig.class, "--foo2=bar2") - .from(TestSource.class) - .namespace("foo").to(TestProcessor.class).namespace("bar") - .run("--foo3=bar3"); - Field parentArgsField = ReflectionUtils.findField(AggregateApplicationBuilder.class,"parentArgs", List.class); - ReflectionUtils.makeAccessible(parentArgsField); - Field parentSourcesField = ReflectionUtils.findField(AggregateApplicationBuilder.class,"parentSources", List.class); - ReflectionUtils.makeAccessible(parentSourcesField); - String args = ReflectionUtils.getField(parentArgsField, aggregateApplicationBuilder).toString(); - Assert.assertEquals(args, argsToVerify.toString()); - List sources = ((List)ReflectionUtils.getField(parentSourcesField, aggregateApplicationBuilder)); - Assert.assertTrue(sources.size() == 3); - Assert.assertTrue(sources.contains(AggregateApplicationBuilder.ParentConfiguration.class)); - Assert.assertTrue(sources.contains(MockBinderRegistryConfiguration.class)); - Assert.assertTrue(sources.contains(DummyConfig.class)); + final ConfigurableApplicationContext context = + aggregateApplicationBuilder.parent(DummyConfig.class, "--foo2=bar2") + .from(TestSource.class) + .namespace("foo").to(TestProcessor.class).namespace("bar") + .run("--foo3=bar3", "--server.port=0"); + DirectFieldAccessor aggregateApplicationBuilderAccessor = new DirectFieldAccessor(aggregateApplicationBuilder); + assertThat((List) aggregateApplicationBuilderAccessor.getPropertyValue( + "parentArgs")).containsExactlyInAnyOrder(argsToVerify.toArray(new String[argsToVerify.size()])); + List sources = (List) aggregateApplicationBuilderAccessor.getPropertyValue("parentSources"); + assertThat(sources).containsExactlyInAnyOrder(AggregateApplicationBuilder.ParentConfiguration.class, + MockBinderRegistryConfiguration.class, DummyConfig.class); + context.close(); } @Test diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/BinderFactoryConfigurationTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/BinderFactoryConfigurationTests.java index a841b5011..d35f5f08a 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/BinderFactoryConfigurationTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/BinderFactoryConfigurationTests.java @@ -25,7 +25,6 @@ import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.stream.aggregate.AggregatorParentConfiguration; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.binder.stub1.StubBinder1; import org.springframework.cloud.stream.binder.stub1.StubBinder1Configuration; @@ -64,7 +63,7 @@ public class BinderFactoryConfigurationTests { public void loadBinderTypeRegistryWithNonSelfContainedAggregatorApp() throws Exception { try { createBinderTestContextWithSources( - new Class[]{SimpleApplication.class, AggregatorParentConfiguration.class}, new String[]{}, + new Class[]{SimpleApplication.class}, new String[]{}, "spring.cloud.stream.internal.selfContained=false"); fail(); } @@ -78,7 +77,7 @@ public class BinderFactoryConfigurationTests { @Test public void loadBinderTypeRegistryWithSelfContainedAggregatorApp() throws Exception { createBinderTestContextWithSources( - new Class[] { SimpleApplication.class, AggregatorParentConfiguration.class}, new String[] {}, + new Class[] { SimpleApplication.class}, new String[] {}, "spring.cloud.stream.internal.selfContained=true"); } diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/HealthIndicatorsConfigurationTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/HealthIndicatorsConfigurationTests.java index 4b5b784f8..49346c70f 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/HealthIndicatorsConfigurationTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/HealthIndicatorsConfigurationTests.java @@ -71,6 +71,7 @@ public class HealthIndicatorsConfigurationTests { assertThat(healthIndicators.get("binder1").health().getStatus()).isEqualTo(Status.UP); assertThat(healthIndicators).containsKey("binder2"); assertThat(healthIndicators.get("binder2").health().getStatus()).isEqualTo(Status.UNKNOWN); + context.close(); } @Test @@ -92,6 +93,7 @@ public class HealthIndicatorsConfigurationTests { } assertThat(context.getBean("testHealthIndicator1", CompositeHealthIndicator.class)).isNotNull(); assertThat(context.getBean("testHealthIndicator2", CompositeHealthIndicator.class)).isNotNull(); + context.close(); } public static ConfigurableApplicationContext createBinderTestContext( diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/InputOutputBindingOrderTest.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/InputOutputBindingOrderTest.java index d460feaea..01e8f400f 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/InputOutputBindingOrderTest.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/InputOutputBindingOrderTest.java @@ -56,6 +56,7 @@ public class InputOutputBindingOrderTest { assertThat(someLifecycle.isRunning()); applicationContext.close(); assertThat(someLifecycle.isRunning()).isFalse(); + applicationContext.close(); } @EnableBinding(Processor.class) diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/LifecycleBinderTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/LifecycleBinderTests.java index b8f70216a..309a54ee7 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/LifecycleBinderTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/LifecycleBinderTests.java @@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class LifecycleBinderTests { @Test - public void testNonSmartLifecyclesStarted() { + public void testOnlySmartLifecyclesStarted() { ConfigurableApplicationContext applicationContext = SpringApplication.run(TestSource.class, "--server.port=-1"); SimpleLifecycle simpleLifecycle = applicationContext.getBean(SimpleLifecycle.class); assertThat(simpleLifecycle.isRunning()).isFalse();