Skip to content

Commit 267a642

Browse files
committed
Reduce duplicate binding of meters to user-defined composites
Fixes gh-42396
1 parent 0aeea6f commit 267a642

File tree

2 files changed

+106
-33
lines changed

2 files changed

+106
-33
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessor.java

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
4242
*/
4343
class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializingSingleton {
4444

45-
private final boolean hasNoCompositeMeterRegistryBeans;
45+
private final CompositeMeterRegistries compositeMeterRegistries;
4646

4747
private final ObjectProvider<MetricsProperties> properties;
4848

@@ -59,17 +59,13 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
5959
MeterRegistryPostProcessor(ApplicationContext applicationContext,
6060
ObjectProvider<MetricsProperties> metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,
6161
ObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {
62-
this(hasNoCompositeMeterRegistryBeans(applicationContext), metricsProperties, customizers, filters, binders);
62+
this(CompositeMeterRegistries.of(applicationContext), metricsProperties, customizers, filters, binders);
6363
}
6464

65-
private static boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) {
66-
return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0;
67-
}
68-
69-
MeterRegistryPostProcessor(boolean hasNoCompositeMeterRegistryBeans, ObjectProvider<MetricsProperties> properties,
70-
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
71-
ObjectProvider<MeterBinder> binders) {
72-
this.hasNoCompositeMeterRegistryBeans = hasNoCompositeMeterRegistryBeans;
65+
MeterRegistryPostProcessor(CompositeMeterRegistries compositeMeterRegistries,
66+
ObjectProvider<MetricsProperties> properties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,
67+
ObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {
68+
this.compositeMeterRegistries = compositeMeterRegistries;
7369
this.properties = properties;
7470
this.customizers = customizers;
7571
this.filters = filters;
@@ -130,11 +126,21 @@ private boolean isGlobalRegistry(MeterRegistry meterRegistry) {
130126
}
131127

132128
private boolean isBindable(MeterRegistry meterRegistry) {
133-
return this.hasNoCompositeMeterRegistryBeans || isCompositeMeterRegistry(meterRegistry);
129+
return isAutoConfiguredComposite(meterRegistry) || isCompositeWithOnlyUserDefinedComposites(meterRegistry)
130+
|| noCompositeMeterRegistries();
131+
}
132+
133+
private boolean isAutoConfiguredComposite(MeterRegistry meterRegistry) {
134+
return meterRegistry instanceof AutoConfiguredCompositeMeterRegistry;
135+
}
136+
137+
private boolean isCompositeWithOnlyUserDefinedComposites(MeterRegistry meterRegistry) {
138+
return this.compositeMeterRegistries == CompositeMeterRegistries.ONLY_USER_DEFINED
139+
&& meterRegistry instanceof CompositeMeterRegistry;
134140
}
135141

136-
private boolean isCompositeMeterRegistry(MeterRegistry meterRegistry) {
137-
return meterRegistry instanceof CompositeMeterRegistry;
142+
private boolean noCompositeMeterRegistries() {
143+
return this.compositeMeterRegistries == CompositeMeterRegistries.NONE;
138144
}
139145

140146
void applyBinders(MeterRegistry meterRegistry) {
@@ -149,4 +155,21 @@ void applyBinders(MeterRegistry meterRegistry) {
149155
this.binders.orderedStream().forEach((binder) -> binder.bindTo(meterRegistry));
150156
}
151157

158+
enum CompositeMeterRegistries {
159+
160+
NONE, AUTO_CONFIGURED, ONLY_USER_DEFINED;
161+
162+
private static CompositeMeterRegistries of(ApplicationContext context) {
163+
if (hasBeansOfType(AutoConfiguredCompositeMeterRegistry.class, context)) {
164+
return AUTO_CONFIGURED;
165+
}
166+
return hasBeansOfType(CompositeMeterRegistry.class, context) ? ONLY_USER_DEFINED : NONE;
167+
}
168+
169+
private static boolean hasBeansOfType(Class<?> type, ApplicationContext context) {
170+
return context.getBeanNamesForType(type, false, false).length > 0;
171+
}
172+
173+
}
174+
152175
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryPostProcessorTests.java

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
1717
package org.springframework.boot.actuate.autoconfigure.metrics;
1818

1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.List;
2122

23+
import io.micrometer.core.instrument.Clock;
2224
import io.micrometer.core.instrument.MeterRegistry;
2325
import io.micrometer.core.instrument.MeterRegistry.Config;
2426
import io.micrometer.core.instrument.Metrics;
@@ -32,6 +34,7 @@
3234
import org.mockito.junit.jupiter.MockitoExtension;
3335

3436
import org.springframework.beans.factory.ObjectProvider;
37+
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryPostProcessor.CompositeMeterRegistries;
3538

3639
import static org.assertj.core.api.Assertions.assertThat;
3740
import static org.mockito.BDDMockito.given;
@@ -76,21 +79,34 @@ class MeterRegistryPostProcessorTests {
7679
}
7780

7881
@Test
79-
void postProcessAndInitializeWhenCompositeAppliesCustomizer() {
82+
void postProcessAndInitializeWhenUserDefinedCompositeAppliesCustomizer() {
8083
this.customizers.add(this.mockCustomizer);
81-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
82-
createObjectProvider(this.properties), createObjectProvider(this.customizers),
83-
createObjectProvider(this.filters), createObjectProvider(this.binders));
84+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
85+
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
86+
createObjectProvider(this.customizers), createObjectProvider(this.filters),
87+
createObjectProvider(this.binders));
8488
CompositeMeterRegistry composite = new CompositeMeterRegistry();
8589
postProcessAndInitialize(processor, composite);
8690
then(this.mockCustomizer).should().customize(composite);
8791
}
8892

93+
@Test
94+
void postProcessAndInitializeWhenAutoConfiguredCompositeAppliesCustomizer() {
95+
this.customizers.add(this.mockCustomizer);
96+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
97+
createObjectProvider(this.properties), createObjectProvider(this.customizers), null,
98+
createObjectProvider(this.binders));
99+
AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,
100+
Collections.emptyList());
101+
postProcessAndInitialize(processor, composite);
102+
then(this.mockCustomizer).should().customize(composite);
103+
}
104+
89105
@Test
90106
void postProcessAndInitializeAppliesCustomizer() {
91107
given(this.mockRegistry.config()).willReturn(this.mockConfig);
92108
this.customizers.add(this.mockCustomizer);
93-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
109+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
94110
createObjectProvider(this.properties), createObjectProvider(this.customizers),
95111
createObjectProvider(this.filters), createObjectProvider(this.binders));
96112
postProcessAndInitialize(processor, this.mockRegistry);
@@ -101,7 +117,7 @@ void postProcessAndInitializeAppliesCustomizer() {
101117
void postProcessAndInitializeAppliesFilter() {
102118
given(this.mockRegistry.config()).willReturn(this.mockConfig);
103119
this.filters.add(this.mockFilter);
104-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
120+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
105121
createObjectProvider(this.properties), createObjectProvider(this.customizers),
106122
createObjectProvider(this.filters), createObjectProvider(this.binders));
107123
postProcessAndInitialize(processor, this.mockRegistry);
@@ -112,41 +128,75 @@ void postProcessAndInitializeAppliesFilter() {
112128
void postProcessAndInitializeBindsTo() {
113129
given(this.mockRegistry.config()).willReturn(this.mockConfig);
114130
this.binders.add(this.mockBinder);
115-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
131+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
116132
createObjectProvider(this.properties), createObjectProvider(this.customizers),
117133
createObjectProvider(this.filters), createObjectProvider(this.binders));
118134
postProcessAndInitialize(processor, this.mockRegistry);
119135
then(this.mockBinder).should().bindTo(this.mockRegistry);
120136
}
121137

122138
@Test
123-
void postProcessAndInitializeWhenCompositeBindsTo() {
139+
void whenUserDefinedCompositeThenPostProcessAndInitializeCompositeBindsTo() {
124140
this.binders.add(this.mockBinder);
125-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
126-
createObjectProvider(this.properties), createObjectProvider(this.customizers),
127-
createObjectProvider(this.filters), createObjectProvider(this.binders));
141+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
142+
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
143+
createObjectProvider(this.customizers), createObjectProvider(this.filters),
144+
createObjectProvider(this.binders));
128145
CompositeMeterRegistry composite = new CompositeMeterRegistry();
129146
postProcessAndInitialize(processor, composite);
130147
then(this.mockBinder).should().bindTo(composite);
131148
}
132149

133150
@Test
134-
void postProcessAndInitializeWhenCompositeExistsDoesNotBindTo() {
151+
void whenUserDefinedCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {
152+
given(this.mockRegistry.config()).willReturn(this.mockConfig);
153+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
154+
CompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),
155+
createObjectProvider(this.customizers), createObjectProvider(this.filters), null);
156+
postProcessAndInitialize(processor, this.mockRegistry);
157+
then(this.mockBinder).shouldHaveNoInteractions();
158+
}
159+
160+
@Test
161+
void whenAutoConfiguredCompositeThenPostProcessAndInitializeAutoConfiguredCompositeBindsTo() {
162+
this.binders.add(this.mockBinder);
163+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
164+
createObjectProvider(this.properties), createObjectProvider(this.customizers), null,
165+
createObjectProvider(this.binders));
166+
AutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,
167+
Collections.emptyList());
168+
postProcessAndInitialize(processor, composite);
169+
then(this.mockBinder).should().bindTo(composite);
170+
}
171+
172+
@Test
173+
void whenAutoConfiguredCompositeThenPostProcessAndInitializeCompositeDoesNotBindTo() {
174+
this.binders.add(this.mockBinder);
175+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
176+
createObjectProvider(this.properties), createObjectProvider(this.customizers),
177+
createObjectProvider(this.filters), null);
178+
CompositeMeterRegistry composite = new CompositeMeterRegistry();
179+
postProcessAndInitialize(processor, composite);
180+
then(this.mockBinder).shouldHaveNoInteractions();
181+
}
182+
183+
@Test
184+
void whenAutoConfiguredCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {
135185
given(this.mockRegistry.config()).willReturn(this.mockConfig);
136-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
186+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,
137187
createObjectProvider(this.properties), createObjectProvider(this.customizers),
138188
createObjectProvider(this.filters), null);
139189
postProcessAndInitialize(processor, this.mockRegistry);
140190
then(this.mockBinder).shouldHaveNoInteractions();
141191
}
142192

143193
@Test
144-
void postProcessAndInitializeBeOrderedCustomizerThenFilterThenBindTo() {
194+
void postProcessAndInitializeIsOrderedCustomizerThenFilterThenBindTo() {
145195
given(this.mockRegistry.config()).willReturn(this.mockConfig);
146196
this.customizers.add(this.mockCustomizer);
147197
this.filters.add(this.mockFilter);
148198
this.binders.add(this.mockBinder);
149-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
199+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
150200
createObjectProvider(this.properties), createObjectProvider(this.customizers),
151201
createObjectProvider(this.filters), createObjectProvider(this.binders));
152202
postProcessAndInitialize(processor, this.mockRegistry);
@@ -160,7 +210,7 @@ void postProcessAndInitializeBeOrderedCustomizerThenFilterThenBindTo() {
160210
void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
161211
given(this.mockRegistry.config()).willReturn(this.mockConfig);
162212
this.properties.setUseGlobalRegistry(true);
163-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
213+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
164214
createObjectProvider(this.properties), createObjectProvider(this.customizers),
165215
createObjectProvider(this.filters), createObjectProvider(this.binders));
166216
try {
@@ -175,7 +225,7 @@ void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
175225
@Test
176226
void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() {
177227
given(this.mockRegistry.config()).willReturn(this.mockConfig);
178-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
228+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
179229
createObjectProvider(this.properties), createObjectProvider(this.customizers),
180230
createObjectProvider(this.filters), createObjectProvider(this.binders));
181231
postProcessAndInitialize(processor, this.mockRegistry);
@@ -186,7 +236,7 @@ void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistr
186236
void postProcessDoesNotBindToUntilSingletonsInitialized() {
187237
given(this.mockRegistry.config()).willReturn(this.mockConfig);
188238
this.binders.add(this.mockBinder);
189-
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
239+
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,
190240
createObjectProvider(this.properties), createObjectProvider(this.customizers),
191241
createObjectProvider(this.filters), createObjectProvider(this.binders));
192242
processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry");

0 commit comments

Comments
 (0)