Avoid actuator beans being ineligible for post-processing

Closes gh-33110
pull/33115/head
Andy Wilkinson 2 years ago
parent b5e502d03b
commit fe72f307f4

@ -21,10 +21,12 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
@ -67,6 +69,7 @@ import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.DispatcherHandler;
/** /**
@ -134,8 +137,9 @@ public class WebFluxEndpointManagementContextConfiguration {
@ConditionalOnBean(EndpointObjectMapper.class) @ConditionalOnBean(EndpointObjectMapper.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor serverCodecConfigurerEndpointObjectMapperBeanPostProcessor( static ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor serverCodecConfigurerEndpointObjectMapperBeanPostProcessor(
EndpointObjectMapper endpointObjectMapper) { ObjectProvider<EndpointObjectMapper> endpointObjectMapper) {
return new ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor(endpointObjectMapper); return new ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor(
SingletonSupplier.of(endpointObjectMapper::getObject));
} }
/** /**
@ -147,9 +151,10 @@ public class WebFluxEndpointManagementContextConfiguration {
private static final List<MediaType> MEDIA_TYPES = Collections private static final List<MediaType> MEDIA_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json"))); .unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
private final EndpointObjectMapper endpointObjectMapper; private final Supplier<EndpointObjectMapper> endpointObjectMapper;
ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor(EndpointObjectMapper endpointObjectMapper) { ServerCodecConfigurerEndpointObjectMapperBeanPostProcessor(
Supplier<EndpointObjectMapper> endpointObjectMapper) {
this.endpointObjectMapper = endpointObjectMapper; this.endpointObjectMapper = endpointObjectMapper;
} }
@ -173,7 +178,7 @@ public class WebFluxEndpointManagementContextConfiguration {
if (encoder instanceof Jackson2JsonEncoder) { if (encoder instanceof Jackson2JsonEncoder) {
Jackson2JsonEncoder jackson2JsonEncoder = (Jackson2JsonEncoder) encoder; Jackson2JsonEncoder jackson2JsonEncoder = (Jackson2JsonEncoder) encoder;
jackson2JsonEncoder.registerObjectMappersForType(OperationResponseBody.class, (associations) -> { jackson2JsonEncoder.registerObjectMappersForType(OperationResponseBody.class, (associations) -> {
ObjectMapper objectMapper = this.endpointObjectMapper.get(); ObjectMapper objectMapper = this.endpointObjectMapper.get().get();
MEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, objectMapper)); MEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, objectMapper));
}); });
} }

@ -44,7 +44,7 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
private final boolean hasNoCompositeMeterRegistryBeans; private final boolean hasNoCompositeMeterRegistryBeans;
private final boolean useGlobalRegistry; private final ObjectProvider<MetricsProperties> properties;
private final ObjectProvider<MeterRegistryCustomizer<?>> customizers; private final ObjectProvider<MeterRegistryCustomizer<?>> customizers;
@ -56,22 +56,21 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
private final Set<MeterRegistry> deferredBindings = new LinkedHashSet<>(); private final Set<MeterRegistry> deferredBindings = new LinkedHashSet<>();
MeterRegistryPostProcessor(ApplicationContext applicationContext, MetricsProperties metricsProperties, MeterRegistryPostProcessor(ApplicationContext applicationContext,
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters, ObjectProvider<MetricsProperties> metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,
ObjectProvider<MeterBinder> binders) { ObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {
this(hasNoCompositeMeterRegistryBeans(applicationContext), metricsProperties.isUseGlobalRegistry(), customizers, this(hasNoCompositeMeterRegistryBeans(applicationContext), metricsProperties, customizers, filters, binders);
filters, binders);
} }
private static boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) { private static boolean hasNoCompositeMeterRegistryBeans(ApplicationContext applicationContext) {
return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0; return applicationContext.getBeanNamesForType(CompositeMeterRegistry.class, false, false).length == 0;
} }
MeterRegistryPostProcessor(boolean hasNoCompositeMeterRegistryBeans, boolean useGlobalRegistry, MeterRegistryPostProcessor(boolean hasNoCompositeMeterRegistryBeans, ObjectProvider<MetricsProperties> properties,
ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters, ObjectProvider<MeterRegistryCustomizer<?>> customizers, ObjectProvider<MeterFilter> filters,
ObjectProvider<MeterBinder> binders) { ObjectProvider<MeterBinder> binders) {
this.hasNoCompositeMeterRegistryBeans = hasNoCompositeMeterRegistryBeans; this.hasNoCompositeMeterRegistryBeans = hasNoCompositeMeterRegistryBeans;
this.useGlobalRegistry = useGlobalRegistry; this.properties = properties;
this.customizers = customizers; this.customizers = customizers;
this.filters = filters; this.filters = filters;
this.binders = binders; this.binders = binders;
@ -121,7 +120,7 @@ class MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializing
} }
private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) { private void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) {
if (this.useGlobalRegistry && !isGlobalRegistry(meterRegistry)) { if (this.properties.getObject().isUseGlobalRegistry() && !isGlobalRegistry(meterRegistry)) {
Metrics.addRegistry(meterRegistry); Metrics.addRegistry(meterRegistry);
} }
} }

@ -51,7 +51,8 @@ public class MetricsAutoConfiguration {
@Bean @Bean
public static MeterRegistryPostProcessor meterRegistryPostProcessor(ApplicationContext applicationContext, public static MeterRegistryPostProcessor meterRegistryPostProcessor(ApplicationContext applicationContext,
MetricsProperties metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers, ObjectProvider<MetricsProperties> metricsProperties,
ObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,
ObjectProvider<MeterFilter> meterFilters, ObjectProvider<MeterBinder> meterBinders) { ObjectProvider<MeterFilter> meterFilters, ObjectProvider<MeterBinder> meterBinders) {
return new MeterRegistryPostProcessor(applicationContext, metricsProperties, meterRegistryCustomizers, return new MeterRegistryPostProcessor(applicationContext, metricsProperties, meterRegistryCustomizers,
meterFilters, meterBinders); meterFilters, meterBinders);

@ -48,6 +48,8 @@ import static org.mockito.Mockito.mock;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class MeterRegistryPostProcessorTests { class MeterRegistryPostProcessorTests {
private final MetricsProperties properties = new MetricsProperties();
private List<MeterRegistryCustomizer<?>> customizers = new ArrayList<>(); private List<MeterRegistryCustomizer<?>> customizers = new ArrayList<>();
private List<MeterFilter> filters = new ArrayList<>(); private List<MeterFilter> filters = new ArrayList<>();
@ -69,12 +71,16 @@ class MeterRegistryPostProcessorTests {
@Mock @Mock
private Config mockConfig; private Config mockConfig;
MeterRegistryPostProcessorTests() {
this.properties.setUseGlobalRegistry(false);
}
@Test @Test
void postProcessAndInitializeWhenCompositeAppliesCustomizer() { void postProcessAndInitializeWhenCompositeAppliesCustomizer() {
this.customizers.add(this.mockCustomizer); this.customizers.add(this.mockCustomizer);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
CompositeMeterRegistry composite = new CompositeMeterRegistry(); CompositeMeterRegistry composite = new CompositeMeterRegistry();
postProcessAndInitialize(processor, composite); postProcessAndInitialize(processor, composite);
then(this.mockCustomizer).should().customize(composite); then(this.mockCustomizer).should().customize(composite);
@ -84,9 +90,9 @@ class MeterRegistryPostProcessorTests {
void postProcessAndInitializeAppliesCustomizer() { void postProcessAndInitializeAppliesCustomizer() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.customizers.add(this.mockCustomizer); this.customizers.add(this.mockCustomizer);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockCustomizer).should().customize(this.mockRegistry); then(this.mockCustomizer).should().customize(this.mockRegistry);
} }
@ -95,9 +101,9 @@ class MeterRegistryPostProcessorTests {
void postProcessAndInitializeAppliesFilter() { void postProcessAndInitializeAppliesFilter() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.filters.add(this.mockFilter); this.filters.add(this.mockFilter);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockConfig).should().meterFilter(this.mockFilter); then(this.mockConfig).should().meterFilter(this.mockFilter);
} }
@ -106,9 +112,9 @@ class MeterRegistryPostProcessorTests {
void postProcessAndInitializeBindsTo() { void postProcessAndInitializeBindsTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.binders.add(this.mockBinder); this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockBinder).should().bindTo(this.mockRegistry); then(this.mockBinder).should().bindTo(this.mockRegistry);
} }
@ -116,9 +122,9 @@ class MeterRegistryPostProcessorTests {
@Test @Test
void postProcessAndInitializeWhenCompositeBindsTo() { void postProcessAndInitializeWhenCompositeBindsTo() {
this.binders.add(this.mockBinder); this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
CompositeMeterRegistry composite = new CompositeMeterRegistry(); CompositeMeterRegistry composite = new CompositeMeterRegistry();
postProcessAndInitialize(processor, composite); postProcessAndInitialize(processor, composite);
then(this.mockBinder).should().bindTo(composite); then(this.mockBinder).should().bindTo(composite);
@ -127,8 +133,9 @@ class MeterRegistryPostProcessorTests {
@Test @Test
void postProcessAndInitializeWhenCompositeExistsDoesNotBindTo() { void postProcessAndInitializeWhenCompositeExistsDoesNotBindTo() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(false,
createObjectProvider(this.customizers), createObjectProvider(this.filters), null); createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), null);
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
then(this.mockBinder).shouldHaveNoInteractions(); then(this.mockBinder).shouldHaveNoInteractions();
} }
@ -139,9 +146,9 @@ class MeterRegistryPostProcessorTests {
this.customizers.add(this.mockCustomizer); this.customizers.add(this.mockCustomizer);
this.filters.add(this.mockFilter); this.filters.add(this.mockFilter);
this.binders.add(this.mockBinder); this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer); InOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer);
then(this.mockCustomizer).should(ordered).customize(this.mockRegistry); then(this.mockCustomizer).should(ordered).customize(this.mockRegistry);
@ -152,9 +159,10 @@ class MeterRegistryPostProcessorTests {
@Test @Test
void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() { void postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, true, this.properties.setUseGlobalRegistry(true);
createObjectProvider(this.customizers), createObjectProvider(this.filters), MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.binders)); createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.filters), createObjectProvider(this.binders));
try { try {
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
assertThat(Metrics.globalRegistry.getRegistries()).contains(this.mockRegistry); assertThat(Metrics.globalRegistry.getRegistries()).contains(this.mockRegistry);
@ -167,9 +175,9 @@ class MeterRegistryPostProcessorTests {
@Test @Test
void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() { void postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
postProcessAndInitialize(processor, this.mockRegistry); postProcessAndInitialize(processor, this.mockRegistry);
assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry); assertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry);
} }
@ -178,9 +186,9 @@ class MeterRegistryPostProcessorTests {
void postProcessDoesNotBindToUntilSingletonsInitialized() { void postProcessDoesNotBindToUntilSingletonsInitialized() {
given(this.mockRegistry.config()).willReturn(this.mockConfig); given(this.mockRegistry.config()).willReturn(this.mockConfig);
this.binders.add(this.mockBinder); this.binders.add(this.mockBinder);
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true, false, MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(true,
createObjectProvider(this.customizers), createObjectProvider(this.filters), createObjectProvider(this.properties), createObjectProvider(this.customizers),
createObjectProvider(this.binders)); createObjectProvider(this.filters), createObjectProvider(this.binders));
processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry"); processor.postProcessAfterInitialization(this.mockRegistry, "meterRegistry");
then(this.mockBinder).shouldHaveNoInteractions(); then(this.mockBinder).shouldHaveNoInteractions();
processor.afterSingletonsInstantiated(); processor.afterSingletonsInstantiated();
@ -199,4 +207,11 @@ class MeterRegistryPostProcessorTests {
return objectProvider; return objectProvider;
} }
@SuppressWarnings("unchecked")
private <T> ObjectProvider<T> createObjectProvider(T object) {
ObjectProvider<T> objectProvider = mock(ObjectProvider.class);
given(objectProvider.getObject()).willReturn(object);
return objectProvider;
}
} }

Loading…
Cancel
Save