From a02fdc755e7f76a03b11685a14f0c563ff9459b2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 13 Feb 2018 09:34:11 +0000 Subject: [PATCH] Stop MeterRegistries when context is closed Closes gh-12006 --- .../AtlasMetricsExportAutoConfiguration.java | 2 +- ...DatadogMetricsExportAutoConfiguration.java | 2 +- ...raphiteMetricsExportAutoConfiguration.java | 2 +- .../InfluxMetricsExportAutoConfiguration.java | 2 +- .../JmxMetricsExportAutoConfiguration.java | 2 +- ...ewRelicMetricsExportAutoConfiguration.java | 2 +- ...ignalFxMetricsExportAutoConfiguration.java | 2 +- .../StatsdMetricsExportAutoConfiguration.java | 2 +- ...asMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- ...ogMetricsExportAutoConfigurationTests.java | 34 +++++++++++++++++- ...iaMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- ...teMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- ...uxMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- ...mxMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- ...icMetricsExportAutoConfigurationTests.java | 35 ++++++++++++++++++- ...FxMetricsExportAutoConfigurationTests.java | 35 ++++++++++++++++++- ...sdMetricsExportAutoConfigurationTests.java | 32 ++++++++++++++++- 17 files changed, 295 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfiguration.java index 2315e7cd20..b92c415b7e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class AtlasMetricsExportAutoConfiguration { return new AtlasPropertiesConfigAdapter(atlasProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public AtlasMeterRegistry atlasMeterRegistry(AtlasConfig atlasConfig, Clock clock) { return new AtlasMeterRegistry(atlasConfig, clock); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfiguration.java index d6b1b109e6..8c6f4aaf6a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfiguration.java @@ -54,7 +54,7 @@ public class DatadogMetricsExportAutoConfiguration { return new DatadogPropertiesConfigAdapter(datadogProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfiguration.java index f8a8f01a8e..b615f7f40f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class GraphiteMetricsExportAutoConfiguration { return new GraphitePropertiesConfigAdapter(graphiteProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig, HierarchicalNameMapper nameMapper, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfiguration.java index 47f55491cf..c8048497bf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfiguration.java @@ -54,7 +54,7 @@ public class InfluxMetricsExportAutoConfiguration { return new InfluxPropertiesConfigAdapter(influxProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfiguration.java index 815baa3233..7dc1b765cf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class JmxMetricsExportAutoConfiguration { return new JmxPropertiesConfigAdapter(jmxProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, HierarchicalNameMapper nameMapper, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfiguration.java index 8a1595af5b..0e8994a96a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class NewRelicMetricsExportAutoConfiguration { return new NewRelicPropertiesConfigAdapter(props); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig config, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfiguration.java index a9a4f7d52e..6102b45753 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class SignalFxMetricsExportAutoConfiguration { return new SignalFxPropertiesConfigAdapter(props); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public SignalFxMeterRegistry signalFxMeterRegistry(SignalFxConfig config, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java index 1a8ce5d21a..7ec09b8641 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java @@ -55,7 +55,7 @@ public class StatsdMetricsExportAutoConfiguration { return new StatsdPropertiesConfigAdapter(statsdProperties); } - @Bean + @Bean(destroyMethod = "stop") @ConditionalOnMissingBean public StatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig, HierarchicalNameMapper hierarchicalNameMapper, Clock clock) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfigurationTests.java index b3226c8782..60e5ad8e3a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.atlas; +import java.util.Map; + import com.netflix.spectator.atlas.AtlasConfig; import io.micrometer.atlas.AtlasMeterRegistry; import io.micrometer.core.instrument.Clock; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link AtlasMetricsExportAutoConfiguration}. @@ -79,6 +85,30 @@ public class AtlasMetricsExportAutoConfigurationTests { .hasSingleBean(AtlasConfig.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + AtlasMeterRegistry registry = spyOnDisposableBean(AtlasMeterRegistry.class, + context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -111,7 +141,7 @@ public class AtlasMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public AtlasMeterRegistry customRegistry(AtlasConfig config, Clock clock) { return new AtlasMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfigurationTests.java index 238b9cb720..2b94c96776 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.datadog; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.datadog.DatadogConfig; import io.micrometer.datadog.DatadogMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link DatadogMetricsExportAutoConfiguration}. @@ -87,6 +93,32 @@ public class DatadogMetricsExportAutoConfigurationTests { .hasBean("customRegistry").hasSingleBean(DatadogConfig.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.metrics.export.datadog.api-key=abcde") + .run((context) -> { + DatadogMeterRegistry registry = spyOnDisposableBean( + DatadogMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -122,7 +154,7 @@ public class DatadogMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public DatadogMeterRegistry customRegistry(DatadogConfig config, Clock clock) { return new DatadogMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/ganglia/GangliaMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/ganglia/GangliaMetricsExportAutoConfigurationTests.java index 2ab24f2b2c..d70974e639 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/ganglia/GangliaMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/ganglia/GangliaMetricsExportAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.ganglia.GangliaConfig; import io.micrometer.ganglia.GangliaMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link GangliaMetricsExportAutoConfiguration}. @@ -79,6 +85,30 @@ public class GangliaMetricsExportAutoConfigurationTests { .hasBean("customRegistry").hasSingleBean(GangliaConfig.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + GangliaMeterRegistry registry = spyOnDisposableBean( + GangliaMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -111,7 +141,7 @@ public class GangliaMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public GangliaMeterRegistry customRegistry(GangliaConfig config, Clock clock) { return new GangliaMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfigurationTests.java index f01ee76c00..88ea9905df 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.graphite; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.graphite.GraphiteConfig; import io.micrometer.graphite.GraphiteMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link GraphiteMetricsExportAutoConfiguration}. @@ -79,6 +85,30 @@ public class GraphiteMetricsExportAutoConfigurationTests { .hasBean("customRegistry").hasSingleBean(GraphiteConfig.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + GraphiteMeterRegistry registry = spyOnDisposableBean( + GraphiteMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -114,7 +144,7 @@ public class GraphiteMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public GraphiteMeterRegistry customRegistry(GraphiteConfig config, Clock clock) { return new GraphiteMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfigurationTests.java index d965c38bd3..f3786bc3e9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.influx; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.influx.InfluxConfig; import io.micrometer.influx.InfluxMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link InfluxMetricsExportAutoConfiguration}. @@ -79,6 +85,30 @@ public class InfluxMetricsExportAutoConfigurationTests { .hasBean("customRegistry").hasSingleBean(InfluxConfig.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + InfluxMeterRegistry registry = spyOnDisposableBean(InfluxMeterRegistry.class, + context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -111,7 +141,7 @@ public class InfluxMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public InfluxMeterRegistry customRegistry(InfluxConfig config, Clock clock) { return new InfluxMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfigurationTests.java index b3a7bce50a..8e088e8c3e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.jmx; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Meter.Id; import io.micrometer.core.instrument.config.NamingConvention; @@ -25,12 +27,16 @@ import io.micrometer.jmx.JmxMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link JmxMetricsExportAutoConfiguration}. @@ -95,6 +101,30 @@ public class JmxMetricsExportAutoConfigurationTests { .hasSingleBean(HierarchicalNameMapper.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + JmxMeterRegistry registry = spyOnDisposableBean(JmxMeterRegistry.class, + context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -127,7 +157,7 @@ public class JmxMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public JmxMeterRegistry customRegistry(JmxConfig config, Clock clock) { return new JmxMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfigurationTests.java index dcbdb3730f..aa42765060 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.influx.InfluxMeterRegistry; import io.micrometer.newrelic.NewRelicConfig; @@ -23,12 +25,16 @@ import io.micrometer.newrelic.NewRelicMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * @@ -102,6 +108,33 @@ public class NewRelicMetricsExportAutoConfigurationTests { .hasBean("customRegistry")); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner + .withPropertyValues("management.metrics.export.newrelic.api-key=abcde", + "management.metrics.export.newrelic.account-id=abcde") + .withUserConfiguration(BaseConfiguration.class).run((context) -> { + NewRelicMeterRegistry registry = spyOnDisposableBean( + NewRelicMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -140,7 +173,7 @@ public class NewRelicMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public NewRelicMeterRegistry customRegistry(NewRelicConfig config, Clock clock) { return new NewRelicMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfigurationTests.java index b881e8bf65..d60b7b8746 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.influx.InfluxMeterRegistry; import io.micrometer.signalfx.SignalFxConfig; @@ -23,12 +25,16 @@ import io.micrometer.signalfx.SignalFxMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link SignalFxMetricsExportAutoConfiguration}. @@ -97,6 +103,33 @@ public class SignalFxMetricsExportAutoConfigurationTests { .hasBean("customRegistry")); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner + .withPropertyValues( + "management.metrics.export.signalfx.access-token=abcde") + .withUserConfiguration(BaseConfiguration.class).run((context) -> { + SignalFxMeterRegistry registry = spyOnDisposableBean( + SignalFxMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -132,7 +165,7 @@ public class SignalFxMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public SignalFxMeterRegistry customRegistry(SignalFxConfig config, Clock clock) { return new SignalFxMeterRegistry(config, clock); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfigurationTests.java index 4dfd449b24..7dc01794de 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.statsd; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Meter.Id; import io.micrometer.core.instrument.config.NamingConvention; @@ -25,12 +27,16 @@ import io.micrometer.statsd.StatsdMeterRegistry; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link StatsdMetricsExportAutoConfiguration}. @@ -94,6 +100,30 @@ public class StatsdMetricsExportAutoConfigurationTests { .hasSingleBean(HierarchicalNameMapper.class)); } + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> { + StatsdMeterRegistry registry = spyOnDisposableBean(StatsdMeterRegistry.class, + context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + @Configuration static class BaseConfiguration { @@ -126,7 +156,7 @@ public class StatsdMetricsExportAutoConfigurationTests { @Import(BaseConfiguration.class) static class CustomRegistryConfiguration { - @Bean + @Bean(destroyMethod = "stop") public StatsdMeterRegistry customRegistry(StatsdConfig config, Clock clock) { return new StatsdMeterRegistry(config, clock); }