Avoid triggering early init when creating MeterRegistryPostProceesor
Closes gh-11890
This commit is contained in:
parent
f19e0258d6
commit
8229733f0d
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} to apply {@link MeterRegistryCustomizer customizers},
|
||||
* {@link MeterFilter filters}, {@link MeterBinder binders} and {@link Metrics#addRegistry
|
||||
* global registration} to {@link MeterRegistry meter registries}. This post processor
|
||||
* intentionally skips {@link CompositeMeterRegistry} with the assumptions that the
|
||||
* registries it contains are beans and will be customized directly.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MeterRegistryConfigurer {
|
||||
|
||||
private final Collection<MeterRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final Collection<MeterFilter> filters;
|
||||
|
||||
private final Collection<MeterBinder> binders;
|
||||
|
||||
private final boolean addToGlobalRegistry;
|
||||
|
||||
MeterRegistryConfigurer(Collection<MeterBinder> binders,
|
||||
Collection<MeterFilter> filters,
|
||||
Collection<MeterRegistryCustomizer<?>> customizers,
|
||||
boolean addToGlobalRegistry) {
|
||||
this.binders = (binders != null ? binders : Collections.emptyList());
|
||||
this.filters = (filters != null ? filters : Collections.emptyList());
|
||||
this.customizers = (customizers != null ? customizers : Collections.emptyList());
|
||||
this.addToGlobalRegistry = addToGlobalRegistry;
|
||||
}
|
||||
|
||||
void configure(MeterRegistry registry) {
|
||||
if (registry instanceof CompositeMeterRegistry) {
|
||||
return;
|
||||
}
|
||||
// Customizers must be applied before binders, as they may add custom tags or
|
||||
// alter timer or summary configuration.
|
||||
customize(registry);
|
||||
addFilters(registry);
|
||||
addBinders(registry);
|
||||
if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) {
|
||||
Metrics.addRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void customize(MeterRegistry registry) {
|
||||
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry)
|
||||
.withLogger(MeterRegistryConfigurer.class)
|
||||
.invoke((customizer) -> customizer.customize(registry));
|
||||
}
|
||||
|
||||
private void addFilters(MeterRegistry registry) {
|
||||
this.filters.forEach(registry.config()::meterFilter);
|
||||
}
|
||||
|
||||
private void addBinders(MeterRegistry registry) {
|
||||
this.binders.forEach((binder) -> binder.bindTo(registry));
|
||||
}
|
||||
|
||||
}
|
|
@ -17,87 +17,56 @@
|
|||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} to apply {@link MeterRegistryCustomizer customizers},
|
||||
* {@link MeterFilter filters}, {@link MeterBinder binders} and {@link Metrics#addRegistry
|
||||
* global registration} to {@link MeterRegistry meter registries}. This post processor
|
||||
* intentionally skips {@link CompositeMeterRegistry} with the assumptions that the
|
||||
* registries it contains are beans and will be customized directly.
|
||||
* {@link BeanPostProcessor} that delegates to a lazily created
|
||||
* {@link MeterRegistryConfigurer} to post-process {@link MeterRegistry} beans.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MeterRegistryPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final Collection<MeterRegistryCustomizer<?>> customizers;
|
||||
private final ApplicationContext context;
|
||||
|
||||
private final Collection<MeterFilter> filters;
|
||||
private volatile MeterRegistryConfigurer configurer;
|
||||
|
||||
private final Collection<MeterBinder> binders;
|
||||
|
||||
private final boolean addToGlobalRegistry;
|
||||
|
||||
MeterRegistryPostProcessor(Collection<MeterBinder> binders,
|
||||
Collection<MeterFilter> filters,
|
||||
Collection<MeterRegistryCustomizer<?>> customizers,
|
||||
boolean addToGlobalRegistry) {
|
||||
this.binders = (binders != null ? binders : Collections.emptyList());
|
||||
this.filters = (filters != null ? filters : Collections.emptyList());
|
||||
this.customizers = (customizers != null ? customizers : Collections.emptyList());
|
||||
this.addToGlobalRegistry = addToGlobalRegistry;
|
||||
MeterRegistryPostProcessor(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof MeterRegistry) {
|
||||
postProcess((MeterRegistry) bean);
|
||||
getConfigurer().configure((MeterRegistry) bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void postProcess(MeterRegistry registry) {
|
||||
if (registry instanceof CompositeMeterRegistry) {
|
||||
return;
|
||||
}
|
||||
// Customizers must be applied before binders, as they may add custom tags or
|
||||
// alter timer or summary configuration.
|
||||
customize(registry);
|
||||
addFilters(registry);
|
||||
addBinders(registry);
|
||||
if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) {
|
||||
Metrics.addRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void customize(MeterRegistry registry) {
|
||||
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry)
|
||||
.withLogger(MeterRegistryPostProcessor.class)
|
||||
.invoke((customizer) -> customizer.customize(registry));
|
||||
private MeterRegistryConfigurer getConfigurer() {
|
||||
if (this.configurer == null) {
|
||||
this.configurer = new MeterRegistryConfigurer(beansOfType(MeterBinder.class),
|
||||
beansOfType(MeterFilter.class),
|
||||
(Collection<MeterRegistryCustomizer<?>>) (Object) beansOfType(
|
||||
MeterRegistryCustomizer.class),
|
||||
this.context.getBean(MetricsProperties.class).isUseGlobalRegistry());
|
||||
}
|
||||
return this.configurer;
|
||||
}
|
||||
|
||||
private void addFilters(MeterRegistry registry) {
|
||||
this.filters.forEach(registry.config()::meterFilter);
|
||||
}
|
||||
|
||||
private void addBinders(MeterRegistry registry) {
|
||||
this.binders.forEach((binder) -> binder.bindTo(registry));
|
||||
private <T> Collection<T> beansOfType(Class<T> type) {
|
||||
return this.context.getBeansOfType(type).values();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,13 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.config.MeterFilter;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsConfiguration;
|
||||
|
@ -40,6 +35,7 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -72,13 +68,8 @@ public class MetricsAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
public static MeterRegistryPostProcessor meterRegistryPostProcessor(
|
||||
ObjectProvider<Collection<MeterBinder>> binders,
|
||||
ObjectProvider<Collection<MeterFilter>> filters,
|
||||
ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers,
|
||||
MetricsProperties properties) {
|
||||
return new MeterRegistryPostProcessor(binders.getIfAvailable(),
|
||||
filters.getIfAvailable(), customizers.getIfAvailable(),
|
||||
properties.isUseGlobalRegistry());
|
||||
ApplicationContext context) {
|
||||
return new MeterRegistryPostProcessor(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -38,11 +38,12 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link MeterRegistryPostProcessor}.
|
||||
* Tests for {@link MeterRegistryConfigurer}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MeterRegistryPostProcessorTests {
|
||||
public class MeterRegistryConfigurerTests {
|
||||
|
||||
private List<MeterBinder> binders = new ArrayList<>();
|
||||
|
||||
|
@ -72,62 +73,50 @@ public class MeterRegistryPostProcessorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenNotRegistryShouldReturnBean() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
Object bean = new Object();
|
||||
String beanName = "name";
|
||||
assertThat(processor.postProcessBeforeInitialization(bean, beanName))
|
||||
.isEqualTo(bean);
|
||||
assertThat(processor.postProcessAfterInitialization(bean, beanName))
|
||||
.isEqualTo(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWhenCompositeShouldSkip() {
|
||||
public void configureWhenCompositeShouldSkip() {
|
||||
this.binders.add(this.mockBinder);
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(new CompositeMeterRegistry(), "name");
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(new CompositeMeterRegistry());
|
||||
verifyZeroInteractions(this.mockBinder, this.mockCustomizer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldApplyCustomizer() {
|
||||
public void configureShouldApplyCustomizer() {
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
verify(this.mockCustomizer).customize(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldApplyFilter() {
|
||||
public void configureShouldApplyFilter() {
|
||||
this.filters.add(this.mockFilter);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
verify(this.mockConfig).meterFilter(this.mockFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldApplyBinder() {
|
||||
public void configureShouldApplyBinder() {
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
verify(this.mockBinder).bindTo(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldBeCallInOrderCustomizeFilterBinder() {
|
||||
public void configureShouldBeCalledInOrderCustomizerFilterBinder() {
|
||||
this.customizers.add(this.mockCustomizer);
|
||||
this.filters.add(this.mockFilter);
|
||||
this.binders.add(this.mockBinder);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer);
|
||||
ordered.verify(this.mockCustomizer).customize(this.mockRegistry);
|
||||
ordered.verify(this.mockConfig).meterFilter(this.mockFilter);
|
||||
|
@ -135,11 +124,11 @@ public class MeterRegistryPostProcessorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, true);
|
||||
public void configureWhenAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, true);
|
||||
try {
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
configurer.configure(this.mockRegistry);
|
||||
assertThat(Metrics.globalRegistry.getRegistries())
|
||||
.contains(this.mockRegistry);
|
||||
}
|
||||
|
@ -149,10 +138,10 @@ public class MeterRegistryPostProcessorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenNotAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.filters, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
public void configureWhenNotAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryConfigurer configurer = new MeterRegistryConfigurer(this.binders,
|
||||
this.filters, this.customizers, false);
|
||||
configurer.configure(this.mockRegistry);
|
||||
assertThat(Metrics.globalRegistry.getRegistries())
|
||||
.doesNotContain(this.mockRegistry);
|
||||
}
|
Loading…
Reference in New Issue