diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactory.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactory.java new file mode 100644 index 000000000000..d69c5da98606 --- /dev/null +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-present 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 + * + * https://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.boot.test.metrics; + +import java.util.List; + +import org.jspecify.annotations.Nullable; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.ContextCustomizerFactory; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.util.ClassUtils; + +/** + * {@link ContextCustomizerFactory} to disable the use of Micrometer's + * {@link io.micrometer.core.instrument.Metrics#globalRegistry global registry} in tests, + * preventing {@link io.micrometer.core.instrument.MeterRegistry meter registries} from + * pinning application contexts when many test contexts are cached. + */ +class DisableGlobalMeterRegistryContextCustomizerFactory implements ContextCustomizerFactory { + + private static final String METRICS_CLASS = "io.micrometer.core.instrument.Metrics"; + + private static final String USE_GLOBAL_REGISTRY_PROPERTY = "management.metrics.use-global-registry"; + + @Override + public @Nullable ContextCustomizer createContextCustomizer(Class testClass, + List configAttributes) { + if (ClassUtils.isPresent(METRICS_CLASS, testClass.getClassLoader())) { + return new DisableGlobalMeterRegistryContextCustomizer(); + } + return null; + } + + static final class DisableGlobalMeterRegistryContextCustomizer implements ContextCustomizer { + + @Override + public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) { + ConfigurableEnvironment environment = context.getEnvironment(); + if (environment.getProperty(USE_GLOBAL_REGISTRY_PROPERTY) == null) { + TestPropertyValues.of(USE_GLOBAL_REGISTRY_PROPERTY + "=false").applyTo(environment); + } + } + + @Override + public boolean equals(@Nullable Object obj) { + return obj instanceof DisableGlobalMeterRegistryContextCustomizer; + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } + + } + +} diff --git a/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/package-info.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/package-info.java new file mode 100644 index 000000000000..4d2792dd73c3 --- /dev/null +++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/metrics/package-info.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-present 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 + * + * https://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. + */ + +/** + * Spring Boot support for metrics testing. + */ +@NullMarked +package org.springframework.boot.test.metrics; + +import org.jspecify.annotations.NullMarked; diff --git a/core/spring-boot-test/src/main/resources/META-INF/spring.factories b/core/spring-boot-test/src/main/resources/META-INF/spring.factories index 8a9b2c7d1412..69d1c39b3217 100644 --- a/core/spring-boot-test/src/main/resources/META-INF/spring.factories +++ b/core/spring-boot-test/src/main/resources/META-INF/spring.factories @@ -5,7 +5,8 @@ org.springframework.boot.test.context.PropertyMappingContextCustomizerFactory,\ org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizerFactory,\ org.springframework.boot.test.context.filter.annotation.TypeExcludeFiltersContextCustomizerFactory,\ org.springframework.boot.test.http.client.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory,\ -org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory +org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory,\ +org.springframework.boot.test.metrics.DisableGlobalMeterRegistryContextCustomizerFactory # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ diff --git a/core/spring-boot-test/src/test/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactoryTests.java b/core/spring-boot-test/src/test/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactoryTests.java new file mode 100644 index 000000000000..fd11852f4bc7 --- /dev/null +++ b/core/spring-boot-test/src/test/java/org/springframework/boot/test/metrics/DisableGlobalMeterRegistryContextCustomizerFactoryTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-present 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 + * + * https://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.boot.test.metrics; + +import org.junit.jupiter.api.Test; +import org.springframework.test.context.MergedContextConfiguration; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.env.StandardEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link DisableGlobalMeterRegistryContextCustomizerFactory}. + */ +class DisableGlobalMeterRegistryContextCustomizerFactoryTests { + + @Test + void disablesGlobalMeterRegistryByDefault() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.setEnvironment(new StandardEnvironment()); + new DisableGlobalMeterRegistryContextCustomizerFactory.DisableGlobalMeterRegistryContextCustomizer() + .customizeContext(context, mock(MergedContextConfiguration.class)); + assertThat(context.getEnvironment().getProperty("management.metrics.use-global-registry")) + .isEqualTo("false"); + } + + @Test + void doesNotOverrideExplicitProperty() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + StandardEnvironment environment = new StandardEnvironment(); + TestPropertyValues.of("management.metrics.use-global-registry=true").applyTo(environment); + context.setEnvironment(environment); + new DisableGlobalMeterRegistryContextCustomizerFactory.DisableGlobalMeterRegistryContextCustomizer() + .customizeContext(context, mock(MergedContextConfiguration.class)); + assertThat(context.getEnvironment().getProperty("management.metrics.use-global-registry")) + .isEqualTo("true"); + } + +} diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java index e3be67195b30..e90937278a1a 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java @@ -54,25 +54,31 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing private final ObjectProvider binders; + private final ObjectProvider meterRegistryCloser; + private volatile boolean deferBinding = true; private final Set deferredBindings = new LinkedHashSet<>(); MeterRegistryPostProcessor(ApplicationContext applicationContext, - ObjectProvider metricsProperties, ObjectProvider> customizers, - ObjectProvider filters, ObjectProvider binders) { - this(CompositeMeterRegistries.of(applicationContext), metricsProperties, customizers, filters, binders); + ObjectProvider metricsProperties, + ObjectProvider> customizers, ObjectProvider filters, + ObjectProvider binders, + ObjectProvider meterRegistryCloser) { + this(CompositeMeterRegistries.of(applicationContext), metricsProperties, customizers, filters, binders, + meterRegistryCloser); } MeterRegistryPostProcessor(CompositeMeterRegistries compositeMeterRegistries, ObjectProvider properties, ObjectProvider> customizers, - ObjectProvider filters, ObjectProvider binders) { + ObjectProvider filters, ObjectProvider binders, + ObjectProvider meterRegistryCloser) { this.compositeMeterRegistries = compositeMeterRegistries; this.properties = properties; this.customizers = customizers; this.filters = filters; this.binders = binders; - + this.meterRegistryCloser = meterRegistryCloser; } @Override @@ -123,6 +129,7 @@ private void applyFilters(MeterRegistry meterRegistry) { private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) { if (this.properties.getObject().isUseGlobalRegistry() && !isGlobalRegistry(meterRegistry)) { Metrics.addRegistry(meterRegistry); + this.meterRegistryCloser.getObject().track(meterRegistry); } } diff --git a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java index 7a4d06b7fee7..7143faf724a0 100644 --- a/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java +++ b/module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java @@ -16,6 +16,9 @@ package org.springframework.boot.micrometer.metrics.autoconfigure; +import java.util.LinkedHashSet; +import java.util.Set; + import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; @@ -65,9 +68,10 @@ Clock micrometerClock() { static MeterRegistryPostProcessor meterRegistryPostProcessor(ApplicationContext applicationContext, ObjectProvider metricsProperties, ObjectProvider> meterRegistryCustomizers, - ObjectProvider meterFilters, ObjectProvider meterBinders) { + ObjectProvider meterFilters, ObjectProvider meterBinders, + ObjectProvider meterRegistryCloser) { return new MeterRegistryPostProcessor(applicationContext, metricsProperties, meterRegistryCustomizers, - meterFilters, meterBinders); + meterFilters, meterBinders, meterRegistryCloser); } @Bean @@ -102,20 +106,25 @@ static class MeterRegistryCloser implements ApplicationListener meterRegistries; - private final boolean useGlobalRegistry; + private final Set trackedRegistries = new LinkedHashSet<>(); + MeterRegistryCloser(ApplicationContext context, boolean useGlobalRegistry) { - this.meterRegistries = context.getBeansOfType(MeterRegistry.class).values(); this.context = context; this.useGlobalRegistry = useGlobalRegistry; } + void track(MeterRegistry meterRegistry) { + this.trackedRegistries.add(meterRegistry); + } + @Override public void onApplicationEvent(ContextClosedEvent event) { if (this.context.equals(event.getApplicationContext())) { - for (MeterRegistry meterRegistry : this.meterRegistries) { + Set meterRegistries = new LinkedHashSet<>(this.trackedRegistries); + meterRegistries.addAll(this.context.getBeansOfType(MeterRegistry.class).values()); + for (MeterRegistry meterRegistry : meterRegistries) { if (this.useGlobalRegistry) { Metrics.globalRegistry.remove(meterRegistry); } diff --git a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java index 0cf3e28d21c2..18bc9402cb38 100644 --- a/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java +++ b/module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java @@ -39,7 +39,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter; +import org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration.MeterRegistryCloser; import org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryPostProcessor.CompositeMeterRegistries; +import org.springframework.context.ApplicationContext; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -84,8 +86,12 @@ class MeterRegistryPostProcessorTests { @SuppressWarnings("NullAway.Init") private Config mockConfig; + private final MetricsAutoConfiguration.MeterRegistryCloser meterRegistryCloser; + MeterRegistryPostProcessorTests() { this.properties.setUseGlobalRegistry(false); + this.meterRegistryCloser = new MetricsAutoConfiguration.MeterRegistryCloser( + mock(ApplicationContext.class), true); } @Test @@ -94,7 +100,7 @@ void postProcessAndInitializeWhenUserDefinedCompositeAppliesCustomizer() { MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties), createObjectProvider(this.customizers), createObjectProvider(this.filters), - createObjectProvider(this.binders)); + createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); CompositeMeterRegistry composite = new CompositeMeterRegistry(); postProcessAndInitialize(processor, composite); then(this.mockCustomizer).should().customize(composite); @@ -105,7 +111,7 @@ void postProcessAndInitializeWhenAutoConfiguredCompositeAppliesCustomizer() { this.customizers.add(this.mockCustomizer); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createEmptyObjectProvider(), createObjectProvider(this.binders)); + createEmptyObjectProvider(), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM, Collections.emptyList()); postProcessAndInitialize(processor, composite); @@ -118,7 +124,7 @@ void postProcessAndInitializeAppliesCustomizer() { this.customizers.add(this.mockCustomizer); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); then(this.mockCustomizer).should().customize(this.mockRegistry); } @@ -129,7 +135,7 @@ void postProcessAndInitializeAppliesFilter() { this.filters.add(this.mockFilter); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); then(this.mockConfig).should().meterFilter(this.mockFilter); } @@ -141,7 +147,7 @@ void postProcessAndInitializeOnlyAppliesLmiitedFiltersToAutoConfigured() { this.filters.add(onlyOnceFilter); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM, Collections.emptyList()); postProcessAndInitialize(processor, composite); @@ -156,7 +162,7 @@ void postProcessAndInitializeBindsTo() { this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); then(this.mockBinder).should().bindTo(this.mockRegistry); } @@ -167,7 +173,7 @@ void whenUserDefinedCompositeThenPostProcessAndInitializeCompositeBindsTo() { MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties), createObjectProvider(this.customizers), createObjectProvider(this.filters), - createObjectProvider(this.binders)); + createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); CompositeMeterRegistry composite = new CompositeMeterRegistry(); postProcessAndInitialize(processor, composite); then(this.mockBinder).should().bindTo(composite); @@ -179,7 +185,7 @@ void whenUserDefinedCompositeThenPostProcessAndInitializeStandardRegistryDoesNot MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor( CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties), createObjectProvider(this.customizers), createObjectProvider(this.filters), - createEmptyObjectProvider()); + createEmptyObjectProvider(), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); then(this.mockBinder).shouldHaveNoInteractions(); } @@ -189,7 +195,7 @@ void whenAutoConfiguredCompositeThenPostProcessAndInitializeAutoConfiguredCompos this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createEmptyObjectProvider(), createObjectProvider(this.binders)); + createEmptyObjectProvider(), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM, Collections.emptyList()); postProcessAndInitialize(processor, composite); @@ -201,7 +207,7 @@ void whenAutoConfiguredCompositeThenPostProcessAndInitializeCompositeDoesNotBind this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createEmptyObjectProvider()); + createObjectProvider(this.filters), createEmptyObjectProvider(), createMeterRegistryCloserProvider(this.meterRegistryCloser)); CompositeMeterRegistry composite = new CompositeMeterRegistry(); postProcessAndInitialize(processor, composite); then(this.mockBinder).shouldHaveNoInteractions(); @@ -212,7 +218,7 @@ void whenAutoConfiguredCompositeThenPostProcessAndInitializeStandardRegistryDoes given(this.mockRegistry.config()).willReturn(this.mockConfig); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createEmptyObjectProvider()); + createObjectProvider(this.filters), createEmptyObjectProvider(), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); then(this.mockBinder).shouldHaveNoInteractions(); } @@ -225,7 +231,7 @@ void postProcessAndInitializeIsOrderedCustomizerThenFilterThenBindTo() { this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer); then(this.mockCustomizer).should(ordered).customize(this.mockRegistry); @@ -233,13 +239,29 @@ void postProcessAndInitializeIsOrderedCustomizerThenFilterThenBindTo() { then(this.mockBinder).should(ordered).bindTo(this.mockRegistry); } + @Test + void trackedRegistryIsRemovedFromGlobalRegistryOnContextClosedEvent() { + ApplicationContext applicationContext = mock(ApplicationContext.class); + MetricsAutoConfiguration.MeterRegistryCloser closer = new MetricsAutoConfiguration.MeterRegistryCloser( + applicationContext, true); + try { + Metrics.addRegistry(this.mockRegistry); + closer.track(this.mockRegistry); + closer.onApplicationEvent(new org.springframework.context.event.ContextClosedEvent(applicationContext)); + assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry); + } + finally { + Metrics.removeRegistry(this.mockRegistry); + } + } + @Test void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() { given(this.mockRegistry.config()).willReturn(this.mockConfig); this.properties.setUseGlobalRegistry(true); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); try { postProcessAndInitialize(processor, this.mockRegistry); assertThat(Metrics.globalRegistry.getRegistries()).contains(this.mockRegistry); @@ -254,7 +276,7 @@ void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistr given(this.mockRegistry.config()).willReturn(this.mockConfig); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); postProcessAndInitialize(processor, this.mockRegistry); assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry); } @@ -265,7 +287,7 @@ void postProcessDoesNotBindToUntilSingletonsInitialized() { this.binders.add(this.mockBinder); MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE, createObjectProvider(this.properties), createObjectProvider(this.customizers), - createObjectProvider(this.filters), createObjectProvider(this.binders)); + createObjectProvider(this.filters), createObjectProvider(this.binders), createMeterRegistryCloserProvider(this.meterRegistryCloser)); processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry"); then(this.mockBinder).shouldHaveNoInteractions(); processor.afterSingletonsInstantiated(); @@ -307,4 +329,20 @@ public Stream orderedStream() { }; } + private ObjectProvider createMeterRegistryCloserProvider(MeterRegistryCloser closer) { + return new ObjectProvider<>() { + + @Override + public MeterRegistryCloser getObject() { + return closer; + } + + @Override + public Stream orderedStream() { + return Stream.of(closer); + } + + }; + } + }