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**
This commit is contained in:
committed by
Gary Russell
parent
cab16c41f4
commit
d60f23549c
@@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.integration.support.management.metrics.CounterFacade;
|
||||
@@ -49,31 +50,44 @@ public class MicrometerMetricsCaptor implements MetricsCaptor {
|
||||
|
||||
public static final String MICROMETER_CAPTOR_NAME = "integrationMicrometerMetricsCaptor";
|
||||
|
||||
protected final MeterRegistry meterRegistry; // NOSONAR
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
private ObjectProvider<MeterRegistry> meterRegistryProvider;
|
||||
|
||||
public MicrometerMetricsCaptor(MeterRegistry meterRegistry) {
|
||||
Assert.notNull(meterRegistry, "meterRegistry cannot be null");
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
MicrometerMetricsCaptor(ObjectProvider<MeterRegistry> meterRegistryProvider) {
|
||||
this.meterRegistryProvider = meterRegistryProvider;
|
||||
}
|
||||
|
||||
public MeterRegistry getMeterRegistry() {
|
||||
if (this.meterRegistry == null) {
|
||||
this.meterRegistry = this.meterRegistryProvider.getIfUnique();
|
||||
}
|
||||
return this.meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimerBuilder timerBuilder(String name) {
|
||||
return new MicroTimerBuilder(this.meterRegistry, name);
|
||||
return new MicroTimerBuilder(getMeterRegistry(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CounterBuilder counterBuilder(String name) {
|
||||
return new MicroCounterBuilder(this.meterRegistry, name);
|
||||
return new MicroCounterBuilder(getMeterRegistry(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GaugeBuilder gaugeBuilder(String name, Object obj, ToDoubleFunction<Object> f) {
|
||||
return new MicroGaugeBuilder(this.meterRegistry, name, obj, f);
|
||||
return new MicroGaugeBuilder(getMeterRegistry(), name, obj, f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleFacade start() {
|
||||
return new MicroSample(Timer.start(this.meterRegistry));
|
||||
return new MicroSample(Timer.start(getMeterRegistry()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,19 +51,16 @@ public class MicrometerMetricsCaptorRegistrar implements ImportBeanDefinitionReg
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
ListableBeanFactory beanFactory = (ListableBeanFactory) registry;
|
||||
if (METER_REGISTRY_CLASS != null
|
||||
&& !registry.containsBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME)) {
|
||||
String[] beanNamesForType =
|
||||
((ListableBeanFactory) registry).getBeanNamesForType(METER_REGISTRY_CLASS, false, false);
|
||||
for (String beanName : beanNamesForType) {
|
||||
registry.registerBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME,
|
||||
BeanDefinitionBuilder.genericBeanDefinition(MicrometerMetricsCaptor.class)
|
||||
.addConstructorArgReference(beanName)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
.getBeanDefinition());
|
||||
return;
|
||||
}
|
||||
&& !registry.containsBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME)
|
||||
&& beanFactory.getBeanNamesForType(METER_REGISTRY_CLASS, false, false).length > 0) {
|
||||
|
||||
registry.registerBeanDefinition(MicrometerMetricsCaptor.MICROMETER_CAPTOR_NAME,
|
||||
BeanDefinitionBuilder.genericBeanDefinition(MicrometerMetricsCaptor.class)
|
||||
.addConstructorArgValue(beanFactory.getBeanProvider(METER_REGISTRY_CLASS))
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,10 @@ import static org.mockito.Mockito.when;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -41,6 +42,7 @@ import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
@@ -69,7 +71,7 @@ public class IntegrationManagementConfigurerTests {
|
||||
channel.setCountsEnabled(true);
|
||||
channel.setStatsEnabled(true);
|
||||
ApplicationContext ctx = mock(ApplicationContext.class);
|
||||
Map<String, IntegrationManagement> beans = new HashMap<String, IntegrationManagement>();
|
||||
Map<String, IntegrationManagement> beans = new HashMap<>();
|
||||
beans.put("foo", channel);
|
||||
beans.put("bar", handler);
|
||||
beans.put("baz", source);
|
||||
@@ -88,14 +90,14 @@ public class IntegrationManagementConfigurerTests {
|
||||
|
||||
@Test
|
||||
public void testEmptyAnnotation() {
|
||||
AnnotationConfigApplicationContext ctx =
|
||||
new AnnotationConfigApplicationContext(ConfigEmptyAnnotation.class);
|
||||
AbstractMessageChannel channel = ctx.getBean("channel", AbstractMessageChannel.class);
|
||||
assertThat(channel.isCountsEnabled()).isTrue();
|
||||
assertThat(channel.isStatsEnabled()).isTrue();
|
||||
channel = ctx.getBean("loggingOffChannel", AbstractMessageChannel.class);
|
||||
assertThat(channel.isLoggingEnabled()).isFalse();
|
||||
ctx.close();
|
||||
try (ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigEmptyAnnotation.class)) {
|
||||
AbstractMessageChannel channel = ctx.getBean("channel", AbstractMessageChannel.class);
|
||||
assertThat(channel.isCountsEnabled()).isTrue();
|
||||
assertThat(channel.isStatsEnabled()).isTrue();
|
||||
assertThat(channel.isLoggingEnabled()).isTrue();
|
||||
channel = ctx.getBean("loggingOffChannel", AbstractMessageChannel.class);
|
||||
assertThat(channel.isLoggingEnabled()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -114,6 +116,7 @@ public class IntegrationManagementConfigurerTests {
|
||||
directChannel.setLoggingEnabled(false);
|
||||
return directChannel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user