Skip to content

Commit f587c08

Browse files
artembilangaryrussell
authored andcommitted
Fix MeterRegistry eager load
If there is a `MeterRegistry` bean (any) in the application context, we add a `MicrometerMetricsCaptor` bean which populates meters further from the components. In some case we may load a `MicrometerMetricsCaptor` bean too early so, not all the stuff around `MeterRegistry` maybe ready. See Spring Boot and its `MetricsAutoConfiguration` * Fix the `MicrometerMetricsCaptorRegistrar` the way to rely on the `ObjectProvider<MeterRegistry>` instead * Add package protected ctor to the `MicrometerMetricsCaptor` to provide a target `MeterRegistry` on demand All of that will ensure that we use an already post-processed `MeterRegistry` including Spring Boot auto-configuration **Cherry-pick to 5.3.x & 5.2.x**
1 parent a2a8764 commit f587c08

File tree

3 files changed

+42
-28
lines changed

3 files changed

+42
-28
lines changed

spring-integration-core/src/main/java/org/springframework/integration/support/management/micrometer/MicrometerMetricsCaptor.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.function.ToDoubleFunction;
2121

2222
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
23+
import org.springframework.beans.factory.ObjectProvider;
2324
import org.springframework.context.ApplicationContext;
2425
import org.springframework.context.support.GenericApplicationContext;
2526
import org.springframework.integration.support.management.metrics.CounterFacade;
@@ -49,31 +50,44 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
4950

5051
public static final String MICROMETER_CAPTOR_NAME = "integrationMicrometerMetricsCaptor";
5152

52-
protected final MeterRegistry meterRegistry; // NOSONAR
53+
private MeterRegistry meterRegistry;
54+
55+
private ObjectProvider<MeterRegistry> meterRegistryProvider;
5356

5457
public MicrometerMetricsCaptor(MeterRegistry meterRegistry) {
5558
Assert.notNull(meterRegistry, "meterRegistry cannot be null");
5659
this.meterRegistry = meterRegistry;
5760
}
5861

62+
MicrometerMetricsCaptor(ObjectProvider<MeterRegistry> meterRegistryProvider) {
63+
this.meterRegistryProvider = meterRegistryProvider;
64+
}
65+
66+
public MeterRegistry getMeterRegistry() {
67+
if (this.meterRegistry == null) {
68+
this.meterRegistry = this.meterRegistryProvider.getIfUnique();
69+
}
70+
return this.meterRegistry;
71+
}
72+
5973
@Override
6074
public TimerBuilder timerBuilder(String name) {
61-
return new MicroTimerBuilder(this.meterRegistry, name);
75+
return new MicroTimerBuilder(getMeterRegistry(), name);
6276
}
6377

6478
@Override
6579
public CounterBuilder counterBuilder(String name) {
66-
return new MicroCounterBuilder(this.meterRegistry, name);
80+
return new MicroCounterBuilder(getMeterRegistry(), name);
6781
}
6882

6983
@Override
7084
public GaugeBuilder gaugeBuilder(String name, Object obj, ToDoubleFunction<Object> f) {
71-
return new MicroGaugeBuilder(this.meterRegistry, name, obj, f);
85+
return new MicroGaugeBuilder(getMeterRegistry(), name, obj, f);
7286
}
7387

7488
@Override
7589
public SampleFacade start() {
76-
return new MicroSample(Timer.start(this.meterRegistry));
90+
return new MicroSample(Timer.start(getMeterRegistry()));
7791
}
7892

7993
@Override

spring-integration-core/src/main/java/org/springframework/integration/support/management/micrometer/MicrometerMetricsCaptorRegistrar.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,16 @@ public class MicrometerMetricsCaptorRegistrar implements ImportBeanDefinitionReg
5151

5252
@Override
5353
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
54+
ListableBeanFactory beanFactory = (ListableBeanFactory) registry;
5455
if (METER_REGISTRY_CLASS != null
55-
&& !registry.containsBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME)) {
56-
String[] beanNamesForType =
57-
((ListableBeanFactory) registry).getBeanNamesForType(METER_REGISTRY_CLASS, false, false);
58-
for (String beanName : beanNamesForType) {
59-
registry.registerBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME,
60-
BeanDefinitionBuilder.genericBeanDefinition(MicrometerMetricsCaptor.class)
61-
.addConstructorArgReference(beanName)
62-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
63-
.getBeanDefinition());
64-
return;
65-
}
56+
&& !registry.containsBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME)
57+
&& beanFactory.getBeanNamesForType(METER_REGISTRY_CLASS, false, false).length > 0) {
6658

59+
registry.registerBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME,
60+
BeanDefinitionBuilder.genericBeanDefinition(MicrometerMetricsCaptor.class)
61+
.addConstructorArgValue(beanFactory.getBeanProvider(METER_REGISTRY_CLASS))
62+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
63+
.getBeanDefinition());
6764
}
6865
}
6966

spring-integration-core/src/test/java/org/springframework/integration/support/management/IntegrationManagementConfigurerTests.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
import java.util.HashMap;
2424
import java.util.Map;
2525

26-
import org.junit.Test;
26+
import org.junit.jupiter.api.Test;
2727

2828
import org.springframework.context.ApplicationContext;
29+
import org.springframework.context.ConfigurableApplicationContext;
2930
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3031
import org.springframework.context.annotation.Bean;
3132
import org.springframework.context.annotation.Configuration;
@@ -42,6 +43,7 @@
4243

4344
/**
4445
* @author Gary Russell
46+
* @author Artem Bilan
4547
*
4648
* @since 4.2
4749
*
@@ -70,7 +72,7 @@ protected Object doReceive() {
7072
channel.setCountsEnabled(true);
7173
channel.setStatsEnabled(true);
7274
ApplicationContext ctx = mock(ApplicationContext.class);
73-
Map<String, IntegrationManagement> beans = new HashMap<String, IntegrationManagement>();
75+
Map<String, IntegrationManagement> beans = new HashMap<>();
7476
beans.put("foo", channel);
7577
beans.put("bar", handler);
7678
beans.put("baz", source);
@@ -89,16 +91,16 @@ protected Object doReceive() {
8991

9092
@Test
9193
public void testEmptyAnnotation() {
92-
AnnotationConfigApplicationContext ctx =
93-
new AnnotationConfigApplicationContext(ConfigEmptyAnnotation.class);
94-
AbstractMessageChannel channel = ctx.getBean("channel", AbstractMessageChannel.class);
95-
assertThat(channel.isCountsEnabled()).isTrue();
96-
assertThat(channel.isStatsEnabled()).isTrue();
97-
assertThat(TestUtils.getPropertyValue(channel, "channelMetrics"))
98-
.isInstanceOf(DefaultMessageChannelMetrics.class);
99-
channel = ctx.getBean("loggingOffChannel", AbstractMessageChannel.class);
100-
assertThat(channel.isLoggingEnabled()).isFalse();
101-
ctx.close();
94+
try (ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigEmptyAnnotation.class)) {
95+
AbstractMessageChannel channel = ctx.getBean("channel", AbstractMessageChannel.class);
96+
assertThat(channel.isCountsEnabled()).isTrue();
97+
assertThat(channel.isStatsEnabled()).isTrue();
98+
assertThat(channel.isLoggingEnabled()).isTrue();
99+
assertThat(TestUtils.getPropertyValue(channel, "channelMetrics"))
100+
.isInstanceOf(DefaultMessageChannelMetrics.class);
101+
channel = ctx.getBean("loggingOffChannel", AbstractMessageChannel.class);
102+
assertThat(channel.isLoggingEnabled()).isFalse();
103+
}
102104
}
103105

104106
@Configuration
@@ -117,6 +119,7 @@ public MessageChannel loggingOffChannel() {
117119
directChannel.setLoggingEnabled(false);
118120
return directChannel;
119121
}
122+
120123
}
121124

122125
}

0 commit comments

Comments
 (0)