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:
Gary Russell
2018-02-15 10:08:30 -05:00
committed by Artem Bilan
parent 11240be555
commit a77def1cdf
2 changed files with 53 additions and 13 deletions

View File

@@ -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")

View File

@@ -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