From 9d7b21a65e4f897388a56bc5ea736fe2888e7739 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Tue, 28 Apr 2026 22:38:09 +0900 Subject: [PATCH] Remove MeterRegistry from global registry on context close See gh-50235 Signed-off-by: Daeho Kwon --- .../metrics/MetricsAutoConfiguration.java | 13 +++++++-- .../MetricsAutoConfigurationTests.java | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index 8aba3d98311..b7da2c6e4fb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics; import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.config.MeterFilter; @@ -70,8 +71,8 @@ public class MetricsAutoConfiguration { } @Bean - MeterRegistryCloser meterRegistryCloser(ApplicationContext context) { - return new MeterRegistryCloser(context); + MeterRegistryCloser meterRegistryCloser(ApplicationContext context, MetricsProperties properties) { + return new MeterRegistryCloser(context, properties.isUseGlobalRegistry()); } /** @@ -84,15 +85,21 @@ public class MetricsAutoConfiguration { private final Iterable meterRegistries; - MeterRegistryCloser(ApplicationContext context) { + private final boolean useGlobalRegistry; + + MeterRegistryCloser(ApplicationContext context, boolean useGlobalRegistry) { this.meterRegistries = context.getBeansOfType(MeterRegistry.class).values(); this.context = context; + this.useGlobalRegistry = useGlobalRegistry; } @Override public void onApplicationEvent(ContextClosedEvent event) { if (this.context.equals(event.getApplicationContext())) { for (MeterRegistry meterRegistry : this.meterRegistries) { + if (this.useGlobalRegistry) { + Metrics.globalRegistry.remove(meterRegistry); + } if (!meterRegistry.isClosed()) { meterRegistry.close(); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java index 000860e2214..8797b3b3405 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.binder.MeterBinder; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; @@ -90,6 +91,33 @@ class MetricsAutoConfigurationTests { }); } + @Test + void meterRegistryCloserShouldRemoveRegistryFromGlobalRegistryOnShutdown() { + this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class).run((context) -> { + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(Metrics.globalRegistry.getRegistries()).contains(meterRegistry); + context.close(); + assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(meterRegistry); + }); + } + + @Test + void meterRegistryCloserShouldNotRemoveRegistryFromGlobalRegistryWhenUseGlobalRegistryIsFalse() { + this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class) + .withPropertyValues("management.metrics.use-global-registry=false") + .run((context) -> { + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + Metrics.globalRegistry.add(meterRegistry); + try { + context.close(); + assertThat(Metrics.globalRegistry.getRegistries()).contains(meterRegistry); + } + finally { + Metrics.globalRegistry.remove(meterRegistry); + } + }); + } + @Test void meterRegistryCloserShouldOnlyCloseRegistriesBelongingToContextBeingClosed() { MeterRegistry parentMeterRegistry = new SimpleMeterRegistry();