Skip to content

Commit a02fdc7

Browse files
committed
Stop MeterRegistries when context is closed
Closes gh-12006
1 parent 9696737 commit a02fdc7

17 files changed

+295
-17
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public AtlasConfig atlasConfig(AtlasProperties atlasProperties) {
5555
return new AtlasPropertiesConfigAdapter(atlasProperties);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public AtlasMeterRegistry atlasMeterRegistry(AtlasConfig atlasConfig, Clock clock) {
6161
return new AtlasMeterRegistry(atlasConfig, clock);

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public DatadogConfig datadogConfig(DatadogProperties datadogProperties) {
5454
return new DatadogPropertiesConfigAdapter(datadogProperties);
5555
}
5656

57-
@Bean
57+
@Bean(destroyMethod = "stop")
5858
@ConditionalOnMissingBean
5959
public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig,
6060
Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphiteMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public GraphiteConfig graphiteConfig(GraphiteProperties graphiteProperties) {
5555
return new GraphitePropertiesConfigAdapter(graphiteProperties);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig,
6161
HierarchicalNameMapper nameMapper, Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public InfluxConfig influxConfig(InfluxProperties influxProperties) {
5454
return new InfluxPropertiesConfigAdapter(influxProperties);
5555
}
5656

57-
@Bean
57+
@Bean(destroyMethod = "stop")
5858
@ConditionalOnMissingBean
5959
public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig,
6060
Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public JmxConfig jmxConfig(JmxProperties jmxProperties) {
5555
return new JmxPropertiesConfigAdapter(jmxProperties);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public JmxMeterRegistry jmxMeterRegistry(JmxConfig config,
6161
HierarchicalNameMapper nameMapper, Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public NewRelicConfig newRelicConfig(NewRelicProperties props) {
5555
return new NewRelicPropertiesConfigAdapter(props);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig config,
6161
Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/signalfx/SignalFxMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public SignalFxConfig signalfxConfig(SignalFxProperties props) {
5555
return new SignalFxPropertiesConfigAdapter(props);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public SignalFxMeterRegistry signalFxMeterRegistry(SignalFxConfig config,
6161
Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public StatsdConfig statsdConfig(StatsdProperties statsdProperties) {
5555
return new StatsdPropertiesConfigAdapter(statsdProperties);
5656
}
5757

58-
@Bean
58+
@Bean(destroyMethod = "stop")
5959
@ConditionalOnMissingBean
6060
public StatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig,
6161
HierarchicalNameMapper hierarchicalNameMapper, Clock clock) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasMetricsExportAutoConfigurationTests.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,24 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.atlas;
1818

19+
import java.util.Map;
20+
1921
import com.netflix.spectator.atlas.AtlasConfig;
2022
import io.micrometer.atlas.AtlasMeterRegistry;
2123
import io.micrometer.core.instrument.Clock;
2224
import org.junit.Test;
2325

2426
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
2528
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2629
import org.springframework.context.annotation.Bean;
2730
import org.springframework.context.annotation.Configuration;
2831
import org.springframework.context.annotation.Import;
32+
import org.springframework.test.util.ReflectionTestUtils;
2933

3034
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.Mockito.spy;
36+
import static org.mockito.Mockito.verify;
3137

3238
/**
3339
* Tests for {@link AtlasMetricsExportAutoConfiguration}.
@@ -79,6 +85,30 @@ public void allowsCustomRegistryToBeUsed() {
7985
.hasSingleBean(AtlasConfig.class));
8086
}
8187

88+
@Test
89+
public void stopsMeterRegistryWhenContextIsClosed() {
90+
this.runner.withUserConfiguration(BaseConfiguration.class).run((context) -> {
91+
AtlasMeterRegistry registry = spyOnDisposableBean(AtlasMeterRegistry.class,
92+
context);
93+
context.close();
94+
verify(registry).stop();
95+
});
96+
}
97+
98+
@SuppressWarnings("unchecked")
99+
private <T> T spyOnDisposableBean(Class<T> type,
100+
AssertableApplicationContext context) {
101+
String[] names = context.getBeanNamesForType(type);
102+
assertThat(names).hasSize(1);
103+
String registryBeanName = names[0];
104+
Map<String, Object> disposableBeans = (Map<String, Object>) ReflectionTestUtils
105+
.getField(context.getAutowireCapableBeanFactory(), "disposableBeans");
106+
Object registryAdapter = disposableBeans.get(registryBeanName);
107+
T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean"));
108+
ReflectionTestUtils.setField(registryAdapter, "bean", registry);
109+
return registry;
110+
}
111+
82112
@Configuration
83113
static class BaseConfiguration {
84114

@@ -111,7 +141,7 @@ public String get(String k) {
111141
@Import(BaseConfiguration.class)
112142
static class CustomRegistryConfiguration {
113143

114-
@Bean
144+
@Bean(destroyMethod = "stop")
115145
public AtlasMeterRegistry customRegistry(AtlasConfig config, Clock clock) {
116146
return new AtlasMeterRegistry(config, clock);
117147
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogMetricsExportAutoConfigurationTests.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,24 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.datadog;
1818

19+
import java.util.Map;
20+
1921
import io.micrometer.core.instrument.Clock;
2022
import io.micrometer.datadog.DatadogConfig;
2123
import io.micrometer.datadog.DatadogMeterRegistry;
2224
import org.junit.Test;
2325

2426
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
2528
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2629
import org.springframework.context.annotation.Bean;
2730
import org.springframework.context.annotation.Configuration;
2831
import org.springframework.context.annotation.Import;
32+
import org.springframework.test.util.ReflectionTestUtils;
2933

3034
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.Mockito.spy;
36+
import static org.mockito.Mockito.verify;
3137

3238
/**
3339
* Tests for {@link DatadogMetricsExportAutoConfiguration}.
@@ -87,6 +93,32 @@ public void allowsCustomRegistryToBeUsed() {
8793
.hasBean("customRegistry").hasSingleBean(DatadogConfig.class));
8894
}
8995

96+
@Test
97+
public void stopsMeterRegistryWhenContextIsClosed() {
98+
this.runner.withUserConfiguration(BaseConfiguration.class)
99+
.withPropertyValues("management.metrics.export.datadog.api-key=abcde")
100+
.run((context) -> {
101+
DatadogMeterRegistry registry = spyOnDisposableBean(
102+
DatadogMeterRegistry.class, context);
103+
context.close();
104+
verify(registry).stop();
105+
});
106+
}
107+
108+
@SuppressWarnings("unchecked")
109+
private <T> T spyOnDisposableBean(Class<T> type,
110+
AssertableApplicationContext context) {
111+
String[] names = context.getBeanNamesForType(type);
112+
assertThat(names).hasSize(1);
113+
String registryBeanName = names[0];
114+
Map<String, Object> disposableBeans = (Map<String, Object>) ReflectionTestUtils
115+
.getField(context.getAutowireCapableBeanFactory(), "disposableBeans");
116+
Object registryAdapter = disposableBeans.get(registryBeanName);
117+
T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean"));
118+
ReflectionTestUtils.setField(registryAdapter, "bean", registry);
119+
return registry;
120+
}
121+
90122
@Configuration
91123
static class BaseConfiguration {
92124

@@ -122,7 +154,7 @@ public String get(String k) {
122154
@Import(BaseConfiguration.class)
123155
static class CustomRegistryConfiguration {
124156

125-
@Bean
157+
@Bean(destroyMethod = "stop")
126158
public DatadogMeterRegistry customRegistry(DatadogConfig config, Clock clock) {
127159
return new DatadogMeterRegistry(config, clock);
128160
}

0 commit comments

Comments
 (0)