Polish 'Support ConfigurationClassPostProcessor supplier'
See gh-22858
This commit is contained in:
parent
06eff45a71
commit
7838c7b072
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,10 +19,12 @@ package org.springframework.boot.autoconfigure;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
|
|
@ -47,6 +49,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
* {@link ConfigurationClassPostProcessor} and Spring Boot.
|
* {@link ConfigurationClassPostProcessor} and Spring Boot.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
class SharedMetadataReaderFactoryContextInitializer
|
class SharedMetadataReaderFactoryContextInitializer
|
||||||
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||||
|
|
@ -56,7 +59,8 @@ class SharedMetadataReaderFactoryContextInitializer
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||||
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor(applicationContext));
|
BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);
|
||||||
|
applicationContext.addBeanFactoryPostProcessor(postProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -69,7 +73,7 @@ class SharedMetadataReaderFactoryContextInitializer
|
||||||
* {@link CachingMetadataReaderFactory} and configure the
|
* {@link CachingMetadataReaderFactory} and configure the
|
||||||
* {@link ConfigurationClassPostProcessor}.
|
* {@link ConfigurationClassPostProcessor}.
|
||||||
*/
|
*/
|
||||||
private static class CachingMetadataReaderFactoryPostProcessor
|
static class CachingMetadataReaderFactoryPostProcessor
|
||||||
implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
|
implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
|
||||||
|
|
||||||
private ConfigurableApplicationContext context;
|
private ConfigurableApplicationContext context;
|
||||||
|
|
@ -103,28 +107,64 @@ class SharedMetadataReaderFactoryContextInitializer
|
||||||
|
|
||||||
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
|
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
|
||||||
try {
|
try {
|
||||||
BeanDefinition definition = registry
|
configureConfigurationClassPostProcessor(
|
||||||
.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
|
registry.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
|
||||||
if (definition instanceof AbstractBeanDefinition) {
|
|
||||||
AbstractBeanDefinition bean = (AbstractBeanDefinition) definition;
|
|
||||||
if (bean.getInstanceSupplier() != null) {
|
|
||||||
Supplier<?> supplier = bean.getInstanceSupplier();
|
|
||||||
bean.setInstanceSupplier(() -> modify(supplier));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
|
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object modify(Supplier<?> supplier) {
|
private void configureConfigurationClassPostProcessor(BeanDefinition definition) {
|
||||||
Object object = supplier.get();
|
if (definition instanceof AbstractBeanDefinition) {
|
||||||
if (object instanceof ConfigurationClassPostProcessor) {
|
configureConfigurationClassPostProcessor((AbstractBeanDefinition) definition);
|
||||||
((ConfigurationClassPostProcessor) object).setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class));
|
return;
|
||||||
}
|
}
|
||||||
return object;
|
configureConfigurationClassPostProcessor(definition.getPropertyValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureConfigurationClassPostProcessor(AbstractBeanDefinition definition) {
|
||||||
|
Supplier<?> instanceSupplier = definition.getInstanceSupplier();
|
||||||
|
if (instanceSupplier != null) {
|
||||||
|
definition.setInstanceSupplier(
|
||||||
|
new ConfigurationClassPostProcessorCustomizingSupplier(this.context, instanceSupplier));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
configureConfigurationClassPostProcessor(definition.getPropertyValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureConfigurationClassPostProcessor(MutablePropertyValues propertyValues) {
|
||||||
|
propertyValues.add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Supplier} used to customize the {@link ConfigurationClassPostProcessor} when
|
||||||
|
* it's first created.
|
||||||
|
*/
|
||||||
|
static class ConfigurationClassPostProcessorCustomizingSupplier implements Supplier<Object> {
|
||||||
|
|
||||||
|
private final ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
private final Supplier<?> instanceSupplier;
|
||||||
|
|
||||||
|
ConfigurationClassPostProcessorCustomizingSupplier(ConfigurableApplicationContext context,
|
||||||
|
Supplier<?> instanceSupplier) {
|
||||||
|
this.context = context;
|
||||||
|
this.instanceSupplier = instanceSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object get() {
|
||||||
|
Object instance = this.instanceSupplier.get();
|
||||||
|
if (instance instanceof ConfigurationClassPostProcessor) {
|
||||||
|
configureConfigurationClassPostProcessor((ConfigurationClassPostProcessor) instance);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureConfigurationClassPostProcessor(ConfigurationClassPostProcessor instance) {
|
||||||
|
instance.setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,32 +19,43 @@ package org.springframework.boot.autoconfigure;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.WebApplicationType;
|
import org.springframework.boot.WebApplicationType;
|
||||||
|
import org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor;
|
||||||
|
import org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory;
|
||||||
import org.springframework.context.ApplicationContextInitializer;
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
|
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link SharedMetadataReaderFactoryContextInitializer}.
|
* Tests for {@link SharedMetadataReaderFactoryContextInitializer}.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
class SharedMetadataReaderFactoryContextInitializerTests {
|
class SharedMetadataReaderFactoryContextInitializerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
void checkOrderOfInitializer() {
|
void checkOrderOfInitializer() {
|
||||||
SpringApplication application = new SpringApplication(TestConfig.class);
|
SpringApplication application = new SpringApplication(TestConfig.class);
|
||||||
application.setWebApplicationType(WebApplicationType.NONE);
|
application.setWebApplicationType(WebApplicationType.NONE);
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<ApplicationContextInitializer<?>> initializers = (List<ApplicationContextInitializer<?>>) ReflectionTestUtils
|
List<ApplicationContextInitializer<?>> initializers = (List<ApplicationContextInitializer<?>>) ReflectionTestUtils
|
||||||
.getField(application, "initializers");
|
.getField(application, "initializers");
|
||||||
// Simulate what would happen if an initializer was added using spring.factories
|
// Simulate what would happen if an initializer was added using spring.factories
|
||||||
|
|
@ -55,6 +66,30 @@ class SharedMetadataReaderFactoryContextInitializerTests {
|
||||||
assertThat(definition.getAttribute("seen")).isEqualTo(true);
|
assertThat(definition.getAttribute("seen")).isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initializeWhenUsingSupplierDecorates() {
|
||||||
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
|
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
|
||||||
|
ConfigurationClassPostProcessor configurationAnnotationPostProcessor = mock(
|
||||||
|
ConfigurationClassPostProcessor.class);
|
||||||
|
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(ConfigurationClassPostProcessor.class).getBeanDefinition();
|
||||||
|
((AbstractBeanDefinition) beanDefinition).setInstanceSupplier(() -> configurationAnnotationPostProcessor);
|
||||||
|
registry.registerBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,
|
||||||
|
beanDefinition);
|
||||||
|
CachingMetadataReaderFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(
|
||||||
|
context);
|
||||||
|
postProcessor.postProcessBeanDefinitionRegistry(registry);
|
||||||
|
context.refresh();
|
||||||
|
ConfigurationClassPostProcessor bean = context.getBean(ConfigurationClassPostProcessor.class);
|
||||||
|
assertThat(bean).isSameAs(configurationAnnotationPostProcessor);
|
||||||
|
ArgumentCaptor<MetadataReaderFactory> metadataReaderFactory = ArgumentCaptor
|
||||||
|
.forClass(MetadataReaderFactory.class);
|
||||||
|
verify(configurationAnnotationPostProcessor).setMetadataReaderFactory(metadataReaderFactory.capture());
|
||||||
|
assertThat(metadataReaderFactory.getValue())
|
||||||
|
.isInstanceOf(ConcurrentReferenceCachingMetadataReaderFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
static class TestConfig {
|
static class TestConfig {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue