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"); | ||||
|  * 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 org.springframework.beans.BeansException; | ||||
| import org.springframework.beans.MutablePropertyValues; | ||||
| import org.springframework.beans.factory.BeanClassLoaderAware; | ||||
| import org.springframework.beans.factory.FactoryBean; | ||||
| import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||||
| 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.RuntimeBeanReference; | ||||
| import org.springframework.beans.factory.support.AbstractBeanDefinition; | ||||
|  | @ -47,6 +49,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory; | |||
|  * {@link ConfigurationClassPostProcessor} and Spring Boot. | ||||
|  * | ||||
|  * @author Phillip Webb | ||||
|  * @author Dave Syer | ||||
|  */ | ||||
| class SharedMetadataReaderFactoryContextInitializer | ||||
| 		implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered { | ||||
|  | @ -56,7 +59,8 @@ class SharedMetadataReaderFactoryContextInitializer | |||
| 
 | ||||
| 	@Override | ||||
| 	public void initialize(ConfigurableApplicationContext applicationContext) { | ||||
| 		applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor(applicationContext)); | ||||
| 		BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext); | ||||
| 		applicationContext.addBeanFactoryPostProcessor(postProcessor); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | @ -69,7 +73,7 @@ class SharedMetadataReaderFactoryContextInitializer | |||
| 	 * {@link CachingMetadataReaderFactory} and configure the | ||||
| 	 * {@link ConfigurationClassPostProcessor}. | ||||
| 	 */ | ||||
| 	private static class CachingMetadataReaderFactoryPostProcessor | ||||
| 	static class CachingMetadataReaderFactoryPostProcessor | ||||
| 			implements BeanDefinitionRegistryPostProcessor, PriorityOrdered { | ||||
| 
 | ||||
| 		private ConfigurableApplicationContext context; | ||||
|  | @ -103,28 +107,64 @@ class SharedMetadataReaderFactoryContextInitializer | |||
| 
 | ||||
| 		private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) { | ||||
| 			try { | ||||
| 				BeanDefinition definition = 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)); | ||||
| 				configureConfigurationClassPostProcessor( | ||||
| 						registry.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); | ||||
| 			} | ||||
| 			catch (NoSuchBeanDefinitionException ex) { | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private Object modify(Supplier<?> supplier) { | ||||
| 			Object object = supplier.get(); | ||||
| 			if (object instanceof ConfigurationClassPostProcessor) { | ||||
| 				((ConfigurationClassPostProcessor) object).setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class)); | ||||
| 		private void configureConfigurationClassPostProcessor(BeanDefinition definition) { | ||||
| 			if (definition instanceof AbstractBeanDefinition) { | ||||
| 				configureConfigurationClassPostProcessor((AbstractBeanDefinition) definition); | ||||
| 				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"); | ||||
|  * 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 org.junit.jupiter.api.Test; | ||||
| import org.mockito.ArgumentCaptor; | ||||
| 
 | ||||
| import org.springframework.beans.BeansException; | ||||
| import org.springframework.beans.factory.config.BeanDefinition; | ||||
| 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.BeanDefinitionRegistryPostProcessor; | ||||
| import org.springframework.boot.SpringApplication; | ||||
| 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.annotation.AnnotationConfigUtils; | ||||
| import org.springframework.context.annotation.ConfigurationClassPostProcessor; | ||||
| import org.springframework.context.support.GenericApplicationContext; | ||||
| import org.springframework.core.type.classreading.MetadataReaderFactory; | ||||
| import org.springframework.test.util.ReflectionTestUtils; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.mockito.Mockito.mock; | ||||
| import static org.mockito.Mockito.verify; | ||||
| 
 | ||||
| /** | ||||
|  * Tests for {@link SharedMetadataReaderFactoryContextInitializer}. | ||||
|  * | ||||
|  * @author Dave Syer | ||||
|  * @author Phillip Webb | ||||
|  */ | ||||
| class SharedMetadataReaderFactoryContextInitializerTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	void checkOrderOfInitializer() { | ||||
| 		SpringApplication application = new SpringApplication(TestConfig.class); | ||||
| 		application.setWebApplicationType(WebApplicationType.NONE); | ||||
| 		@SuppressWarnings("unchecked") | ||||
| 		List<ApplicationContextInitializer<?>> initializers = (List<ApplicationContextInitializer<?>>) ReflectionTestUtils | ||||
| 				.getField(application, "initializers"); | ||||
| 		// Simulate what would happen if an initializer was added using spring.factories | ||||
|  | @ -55,6 +66,30 @@ class SharedMetadataReaderFactoryContextInitializerTests { | |||
| 		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 { | ||||
| 
 | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue