Skip to content

Commit a77def1

Browse files
garyrussellartembilan
authored andcommitted
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`.
1 parent 11240be commit a77def1

File tree

2 files changed

+53
-13
lines changed

2 files changed

+53
-13
lines changed

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

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.BeansException;
2828
import org.springframework.beans.factory.BeanNameAware;
2929
import org.springframework.beans.factory.SmartInitializingSingleton;
30+
import org.springframework.beans.factory.config.BeanPostProcessor;
3031
import org.springframework.context.ApplicationContext;
3132
import org.springframework.context.ApplicationContextAware;
3233
import org.springframework.integration.support.management.IntegrationManagement.ManagementOverrides;
@@ -47,7 +48,7 @@
4748
*
4849
*/
4950
public class IntegrationManagementConfigurer implements SmartInitializingSingleton, ApplicationContextAware,
50-
BeanNameAware {
51+
BeanNameAware, BeanPostProcessor {
5152

5253
private static final Log logger = LogFactory.getLog(IntegrationManagementConfigurer.class);
5354

@@ -59,6 +60,8 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
5960

6061
private final Map<String, MessageSourceMetrics> sourcesByName = new HashMap<String, MessageSourceMetrics>();
6162

63+
private final Map<String, MessageSourceMetricsConfigurer> sourceConfigurers = new HashMap<>();
64+
6265
private ApplicationContext applicationContext;
6366

6467
private String beanName;
@@ -77,6 +80,8 @@ public class IntegrationManagementConfigurer implements SmartInitializingSinglet
7780

7881
private String[] enabledStatsPatterns = { };
7982

83+
private volatile boolean singletonsInstantiated;
84+
8085
@Override
8186
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
8287
this.applicationContext = applicationContext;
@@ -212,26 +217,39 @@ public void afterSingletonsInstantiated() {
212217
if (this.metricsFactory == null) {
213218
this.metricsFactory = new DefaultMetricsFactory();
214219
}
215-
Map<String, MessageSourceMetricsConfigurer> sourceConfigurers = this.applicationContext
216-
.getBeansOfType(MessageSourceMetricsConfigurer.class);
220+
this.sourceConfigurers.putAll(this.applicationContext.getBeansOfType(MessageSourceMetricsConfigurer.class));
217221
Map<String, IntegrationManagement> managed = this.applicationContext.getBeansOfType(IntegrationManagement.class);
218222
for (Entry<String, IntegrationManagement> entry : managed.entrySet()) {
219223
IntegrationManagement bean = entry.getValue();
220224
if (!bean.getOverrides().loggingConfigured) {
221225
bean.setLoggingEnabled(this.defaultLoggingEnabled);
222226
}
223227
String name = entry.getKey();
224-
if (bean instanceof MessageChannelMetrics) {
225-
configureChannelMetrics(name, (MessageChannelMetrics) bean);
226-
}
227-
else if (bean instanceof MessageHandlerMetrics) {
228-
configureHandlerMetrics(name, (MessageHandlerMetrics) bean);
229-
}
230-
else if (bean instanceof MessageSourceMetrics) {
231-
configureSourceMetrics(name, (MessageSourceMetrics) bean);
232-
sourceConfigurers.values().forEach(c -> c.configure((MessageSourceMetrics) bean, name));
233-
}
228+
doConfigureMetrics(bean, name);
229+
}
230+
this.singletonsInstantiated = true;
231+
}
232+
233+
@Override
234+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
235+
if (this.singletonsInstantiated) {
236+
return doConfigureMetrics(bean, beanName);
237+
}
238+
return bean;
239+
}
240+
241+
private Object doConfigureMetrics(Object bean, String name) {
242+
if (bean instanceof MessageChannelMetrics) {
243+
configureChannelMetrics(name, (MessageChannelMetrics) bean);
244+
}
245+
else if (bean instanceof MessageHandlerMetrics) {
246+
configureHandlerMetrics(name, (MessageHandlerMetrics) bean);
247+
}
248+
else if (bean instanceof MessageSourceMetrics) {
249+
configureSourceMetrics(name, (MessageSourceMetrics) bean);
250+
this.sourceConfigurers.values().forEach(c -> c.configure((MessageSourceMetrics) bean, name));
234251
}
252+
return bean;
235253
}
236254

237255
@SuppressWarnings("unchecked")

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,21 @@
2525
import org.junit.runner.RunWith;
2626

2727
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
29+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
30+
import org.springframework.context.ConfigurableApplicationContext;
2831
import org.springframework.context.annotation.Bean;
2932
import org.springframework.context.annotation.Configuration;
3033
import org.springframework.integration.annotation.ServiceActivator;
3134
import org.springframework.integration.channel.AbstractMessageChannel;
3235
import org.springframework.integration.channel.AbstractPollableChannel;
36+
import org.springframework.integration.channel.DirectChannel;
3337
import org.springframework.integration.channel.QueueChannel;
3438
import org.springframework.integration.config.EnableIntegration;
3539
import org.springframework.integration.config.EnableIntegrationManagement;
3640
import org.springframework.integration.core.MessageSource;
3741
import org.springframework.integration.endpoint.AbstractMessageSource;
42+
import org.springframework.integration.test.util.TestUtils;
3843
import org.springframework.messaging.Message;
3944
import org.springframework.messaging.MessagingException;
4045
import org.springframework.messaging.PollableChannel;
@@ -59,6 +64,9 @@
5964
@DirtiesContext
6065
public class MicrometerMetricsTests {
6166

67+
@Autowired
68+
private ConfigurableApplicationContext context;
69+
6270
@Autowired
6371
private MeterRegistry meterRegistry;
6472

@@ -146,6 +154,20 @@ public void testSend() {
146154
default:
147155
}
148156
}
157+
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) this.context.getBeanFactory();
158+
beanFactory.registerBeanDefinition("newChannel",
159+
BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class).getRawBeanDefinition());
160+
DirectChannel newChannel = this.context.getBean("newChannel", DirectChannel.class);
161+
assertThat(this.meterRegistry.getMeters().size()).isEqualTo(24);
162+
Timer timer = meterRegistry.get("newChannel.timer").timer();
163+
assertThat(timer).isSameAs(TestUtils.getPropertyValue(newChannel, "channelMetrics.timer"));
164+
beanFactory.removeBeanDefinition("newChannel");
165+
// verify that the meter registry reuses the existing timer
166+
beanFactory.registerBeanDefinition("newChannel",
167+
BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class).getRawBeanDefinition());
168+
newChannel = this.context.getBean("newChannel", DirectChannel.class);
169+
assertThat(this.meterRegistry.getMeters().size()).isEqualTo(24);
170+
assertThat(timer).isSameAs(TestUtils.getPropertyValue(newChannel, "channelMetrics.timer"));
149171
}
150172

151173
@Configuration

0 commit comments

Comments
 (0)