Browse Source

Avoid eager initialization when configuring Data repository metrics

Fixes gh-26630
pull/26635/head
Andy Wilkinson 5 years ago
parent
commit
7a7050879c
  1. 28
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/MetricsRepositoryMethodInvocationListenerBeanPostProcessor.java
  2. 5
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java
  3. 2
      spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/data/MetricsRepositoryMethodInvocationListenerBeanPostProcessorTests.java
  4. 18
      spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfigurationTests.java

28
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/MetricsRepositoryMethodInvocationListenerBeanPostProcessor.java

@ -16,6 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics.data; package org.springframework.boot.actuate.autoconfigure.metrics.data;
import java.util.function.Supplier;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener; import org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener;
@ -33,8 +35,9 @@ class MetricsRepositoryMethodInvocationListenerBeanPostProcessor implements Bean
private final RepositoryFactoryCustomizer customizer; private final RepositoryFactoryCustomizer customizer;
MetricsRepositoryMethodInvocationListenerBeanPostProcessor(MetricsRepositoryMethodInvocationListener listener) { MetricsRepositoryMethodInvocationListenerBeanPostProcessor(
this.customizer = (repositoryFactory) -> repositoryFactory.addInvocationListener(listener); Supplier<MetricsRepositoryMethodInvocationListener> listener) {
this.customizer = new MetricsRepositoryFactoryCustomizer(listener);
} }
@Override @Override
@ -45,4 +48,25 @@ class MetricsRepositoryMethodInvocationListenerBeanPostProcessor implements Bean
return bean; return bean;
} }
private static final class MetricsRepositoryFactoryCustomizer implements RepositoryFactoryCustomizer {
private final Supplier<MetricsRepositoryMethodInvocationListener> listenerSupplier;
private volatile MetricsRepositoryMethodInvocationListener listener;
private MetricsRepositoryFactoryCustomizer(
Supplier<MetricsRepositoryMethodInvocationListener> listenerSupplier) {
this.listenerSupplier = listenerSupplier;
}
@Override
public void customize(RepositoryFactorySupport repositoryFactory) {
if (this.listener == null) {
this.listener = this.listenerSupplier.get();
}
repositoryFactory.addInvocationListener(this.listener);
}
}
} }

5
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfiguration.java

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics.data;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
@ -72,9 +73,9 @@ public class RepositoryMetricsAutoConfiguration {
@Bean @Bean
public static MetricsRepositoryMethodInvocationListenerBeanPostProcessor metricsRepositoryMethodInvocationListenerBeanPostProcessor( public static MetricsRepositoryMethodInvocationListenerBeanPostProcessor metricsRepositoryMethodInvocationListenerBeanPostProcessor(
MetricsRepositoryMethodInvocationListener metricsRepositoryMethodInvocationListener) { ObjectProvider<MetricsRepositoryMethodInvocationListener> metricsRepositoryMethodInvocationListener) {
return new MetricsRepositoryMethodInvocationListenerBeanPostProcessor( return new MetricsRepositoryMethodInvocationListenerBeanPostProcessor(
metricsRepositoryMethodInvocationListener); metricsRepositoryMethodInvocationListener::getObject);
} }
} }

2
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/data/MetricsRepositoryMethodInvocationListenerBeanPostProcessorTests.java

@ -38,7 +38,7 @@ class MetricsRepositoryMethodInvocationListenerBeanPostProcessorTests {
private MetricsRepositoryMethodInvocationListener listener = mock(MetricsRepositoryMethodInvocationListener.class); private MetricsRepositoryMethodInvocationListener listener = mock(MetricsRepositoryMethodInvocationListener.class);
private MetricsRepositoryMethodInvocationListenerBeanPostProcessor postProcessor = new MetricsRepositoryMethodInvocationListenerBeanPostProcessor( private MetricsRepositoryMethodInvocationListenerBeanPostProcessor postProcessor = new MetricsRepositoryMethodInvocationListenerBeanPostProcessor(
this.listener); () -> this.listener);
@Test @Test
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")

18
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/data/RepositoryMetricsAutoConfigurationTests.java

@ -24,6 +24,7 @@ import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.MeterBinder;
import io.micrometer.core.instrument.distribution.HistogramSnapshot; import io.micrometer.core.instrument.distribution.HistogramSnapshot;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -125,6 +126,13 @@ class RepositoryMetricsAutoConfigurationTests {
}); });
} }
@Test
void doesNotTriggerEarlyInitializationThatPreventsMeterBindersFromBindingMeters() {
this.contextRunner.withUserConfiguration(MeterBinderConfiguration.class)
.run((context) -> assertThat(context.getBean(MeterRegistry.class).find("binder.test").counter())
.isNotNull());
}
private MeterRegistry getInitializedMeterRegistry(AssertableApplicationContext context, private MeterRegistry getInitializedMeterRegistry(AssertableApplicationContext context,
Class<?> repositoryInterface) { Class<?> repositoryInterface) {
MetricsRepositoryMethodInvocationListener listener = context MetricsRepositoryMethodInvocationListener listener = context
@ -158,6 +166,16 @@ class RepositoryMetricsAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false)
static class MeterBinderConfiguration {
@Bean
MeterBinder meterBinder() {
return (registry) -> registry.counter("binder.test");
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class MetricsRepositoryMethodInvocationListenerConfiguration { static class MetricsRepositoryMethodInvocationListenerConfiguration {

Loading…
Cancel
Save