INT-4403: Micrometer and Dynamic Components
JIRA: https://jira.spring.io/browse/INT-4402 Previously, Micrometer instrumentation was only applied to components during ApplicationContext initialization. `IntegrationManagementConfigurer` is now a `BeanPostProcessor` as well as a `SmartInitializingSingleton`, but only acts as a BPP after the context is initialized. This enables Micrometer instrumentation to beans added later, either via a new `BeanDefinition` or `bf.initializeBean`. NOTE: destroying and re-creating a bean will use the same `Meters`.
This commit is contained in:
committed by
Artem Bilan
parent
11240be555
commit
a77def1cdf
@@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.integration.support.management.IntegrationManagement.ManagementOverrides;
|
||||
@@ -47,7 +48,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
*/
|
||||
public class IntegrationManagementConfigurer implements SmartInitializingSingleton, ApplicationContextAware,
|
||||
BeanNameAware {
|
||||
BeanNameAware, BeanPostProcessor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(IntegrationManagementConfigurer.class);
|
||||
|
||||
@@ -59,6 +60,8 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
|
||||
|
||||
private final Map<String, MessageSourceMetrics> sourcesByName = new HashMap<String, MessageSourceMetrics>();
|
||||
|
||||
private final Map<String, MessageSourceMetricsConfigurer> sourceConfigurers = new HashMap<>();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private String beanName;
|
||||
@@ -77,6 +80,8 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
|
||||
|
||||
private String[] enabledStatsPatterns = { };
|
||||
|
||||
private volatile boolean singletonsInstantiated;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
@@ -212,8 +217,7 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
|
||||
if (this.metricsFactory == null) {
|
||||
this.metricsFactory = new DefaultMetricsFactory();
|
||||
}
|
||||
Map<String, MessageSourceMetricsConfigurer> sourceConfigurers = this.applicationContext
|
||||
.getBeansOfType(MessageSourceMetricsConfigurer.class);
|
||||
this.sourceConfigurers.putAll(this.applicationContext.getBeansOfType(MessageSourceMetricsConfigurer.class));
|
||||
Map<String, IntegrationManagement> managed = this.applicationContext.getBeansOfType(IntegrationManagement.class);
|
||||
for (Entry<String, IntegrationManagement> entry : managed.entrySet()) {
|
||||
IntegrationManagement bean = entry.getValue();
|
||||
@@ -221,17 +225,31 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
|
||||
bean.setLoggingEnabled(this.defaultLoggingEnabled);
|
||||
}
|
||||
String name = entry.getKey();
|
||||
if (bean instanceof MessageChannelMetrics) {
|
||||
configureChannelMetrics(name, (MessageChannelMetrics) bean);
|
||||
}
|
||||
else if (bean instanceof MessageHandlerMetrics) {
|
||||
configureHandlerMetrics(name, (MessageHandlerMetrics) bean);
|
||||
}
|
||||
else if (bean instanceof MessageSourceMetrics) {
|
||||
configureSourceMetrics(name, (MessageSourceMetrics) bean);
|
||||
sourceConfigurers.values().forEach(c -> c.configure((MessageSourceMetrics) bean, name));
|
||||
}
|
||||
doConfigureMetrics(bean, name);
|
||||
}
|
||||
this.singletonsInstantiated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (this.singletonsInstantiated) {
|
||||
return doConfigureMetrics(bean, beanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private Object doConfigureMetrics(Object bean, String name) {
|
||||
if (bean instanceof MessageChannelMetrics) {
|
||||
configureChannelMetrics(name, (MessageChannelMetrics) bean);
|
||||
}
|
||||
else if (bean instanceof MessageHandlerMetrics) {
|
||||
configureHandlerMetrics(name, (MessageHandlerMetrics) bean);
|
||||
}
|
||||
else if (bean instanceof MessageSourceMetrics) {
|
||||
configureSourceMetrics(name, (MessageSourceMetrics) bean);
|
||||
this.sourceConfigurers.values().forEach(c -> c.configure((MessageSourceMetrics) bean, name));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -25,16 +25,21 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.channel.AbstractPollableChannel;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.config.EnableIntegrationManagement;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.endpoint.AbstractMessageSource;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
@@ -59,6 +64,9 @@ import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
@DirtiesContext
|
||||
public class MicrometerMetricsTests {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
@@ -146,6 +154,20 @@ public class MicrometerMetricsTests {
|
||||
default:
|
||||
}
|
||||
}
|
||||
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) this.context.getBeanFactory();
|
||||
beanFactory.registerBeanDefinition("newChannel",
|
||||
BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class).getRawBeanDefinition());
|
||||
DirectChannel newChannel = this.context.getBean("newChannel", DirectChannel.class);
|
||||
assertThat(this.meterRegistry.getMeters().size()).isEqualTo(24);
|
||||
Timer timer = meterRegistry.get("newChannel.timer").timer();
|
||||
assertThat(timer).isSameAs(TestUtils.getPropertyValue(newChannel, "channelMetrics.timer"));
|
||||
beanFactory.removeBeanDefinition("newChannel");
|
||||
// verify that the meter registry reuses the existing timer
|
||||
beanFactory.registerBeanDefinition("newChannel",
|
||||
BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class).getRawBeanDefinition());
|
||||
newChannel = this.context.getBean("newChannel", DirectChannel.class);
|
||||
assertThat(this.meterRegistry.getMeters().size()).isEqualTo(24);
|
||||
assertThat(timer).isSameAs(TestUtils.getPropertyValue(newChannel, "channelMetrics.timer"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
Reference in New Issue
Block a user