From e65baba3a7f327bc17d05225953b6525902df2bb Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 28 Nov 2025 09:24:49 +0000 Subject: [PATCH] Polish "Stop closing parent's MeterRegistry beans when child context closes" See gh-48319 --- .../metrics/MetricsAutoConfiguration.java | 19 +++++++++----- .../MetricsAutoConfigurationTests.java | 25 +++++++++++-------- 2 files changed, 27 insertions(+), 17 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 9da104ab807..8aba3d98311 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 @@ -70,8 +70,8 @@ public class MetricsAutoConfiguration { } @Bean - MeterRegistryCloser meterRegistryCloser() { - return new MeterRegistryCloser(); + MeterRegistryCloser meterRegistryCloser(ApplicationContext context) { + return new MeterRegistryCloser(context); } /** @@ -80,12 +80,19 @@ public class MetricsAutoConfiguration { */ static class MeterRegistryCloser implements ApplicationListener { + private final ApplicationContext context; + + private final Iterable meterRegistries; + + MeterRegistryCloser(ApplicationContext context) { + this.meterRegistries = context.getBeansOfType(MeterRegistry.class).values(); + this.context = context; + } + @Override public void onApplicationEvent(ContextClosedEvent event) { - if (event.getApplicationContext().getParent() == null) { - for (MeterRegistry meterRegistry : event.getApplicationContext() - .getBeansOfType(MeterRegistry.class) - .values()) { + if (this.context.equals(event.getApplicationContext())) { + for (MeterRegistry meterRegistry : this.meterRegistries) { 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 33394dedd10..000860e2214 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 @@ -30,7 +30,6 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.test.util.ReflectionTestUtils; @@ -92,17 +91,21 @@ class MetricsAutoConfigurationTests { } @Test - void meterRegistryCloserShouldNotCloseOnNonRootContextClosing() { - this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class).run((context) -> { - MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); - GenericApplicationContext childContext = new GenericApplicationContext(); - childContext.setParent(context); - childContext.refresh(); - childContext.close(); - assertThat(meterRegistry.isClosed()).isFalse(); - context.close(); - assertThat(meterRegistry.isClosed()).isTrue(); + void meterRegistryCloserShouldOnlyCloseRegistriesBelongingToContextBeingClosed() { + MeterRegistry parentMeterRegistry = new SimpleMeterRegistry(); + MeterRegistry childMeterRegistry = new SimpleMeterRegistry(); + this.contextRunner.withBean(MeterRegistry.class, () -> parentMeterRegistry).run((parent) -> { + this.contextRunner.withBean(MeterRegistry.class, () -> childMeterRegistry) + .withParent(parent) + .run((child) -> { + assertThat(childMeterRegistry.isClosed()).isFalse(); + assertThat(parentMeterRegistry.isClosed()).isFalse(); + }); + assertThat(childMeterRegistry.isClosed()).isTrue(); + assertThat(parentMeterRegistry.isClosed()).isFalse(); }); + assertThat(childMeterRegistry.isClosed()).isTrue(); + assertThat(parentMeterRegistry.isClosed()).isTrue(); } @Configuration(proxyBeanMethods = false)