ConfigurationClassPostProcessor


用于在容器启动过程中处理标注@Configuration类的BeanFactoryPostProcessor 。在xml配置文件中使用<context:annotation-config/>or <context:component-scan/>都会注册这个后置处理器。这个Bean非常重要,因为在标注@Configuration的类中包含了其他需要进行注册的Bean定义,所以在与其他相同类型后置处理器一起使用时,优先级较高,因此通过实现了接口PriorityOrdered来保证初始化的顺序性。
首先看一下这个类的结构图:
在这里插入图片描述
从这个图不难看出,通过多个Aware{ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware},引入了资源加载工具类ResoureLoader和环境参数Environment、类加载器ClassLoader。当然最重要的还是BeanDefinitionRegistryPostProcessor这个接口了。作为一个标准的BeanFactoryPostProcessor的SPI扩展,允许在常规的BeanFactoryPostProcessor起作用之前进行Bean的注册(通常也可以用于进行BeanFactoryPostProcessor类型Bean的注册)。主要的方法如下所示:

/**
 * Modify the application context's internal bean definition registry after its
 * standard initialization. All regular bean definitions will have been loaded,
 * but no beans will have been instantiated yet. This allows for adding further
 * bean definitions before the next post-processing phase kicks in.
 * @param registry the bean definition registry used by the application context
 * @throws org.springframework.beans.BeansException in case of errors
 */
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

另外BeanDefinitionRegistryPostProcessor也继承了BeanFactoryPostProcessor,后者主要用于在Bean开始创建之前对Bean的定义进行修改操作的。其中最为人所知的就是PropertyResourceConfigurer.这个接口定义的方法为

/**
 * Modify the application context's internal bean factory after its standard
 * initialization. All bean definitions will have been loaded, but no beans
 * will have been instantiated yet. This allows for overriding or adding
 * properties even to eager-initializing beans.
 * @param beanFactory the bean factory used by the application context
 * @throws org.springframework.beans.BeansException in case of errors
 */
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

ConfigurationClassPostProcessor中首先起作用的是那三个Aware方法,然后是postProcessBeanDefinitionRegistry,最后是postProcessBeanFactory

注册的时机

那么ConfigurationClassPostProcessor是何时注册到Spring容器中的呢?其实在Spring容器创建的时候就会注册一些基础的bean,ConfigurationClassPostProcessor就是其中的一员。
参考博客Spring创建容器时就存在的5个Beanhttps://blog.csdn.net/m0_37607945/article/details/106418334

执行时机

主要参考PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		processedBeans.add(ppName);
	}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();

首先会从Spring的Bean定义工厂中查找到ConfigurationClassPostProcessor并进行初始化,ConfigurationClassPostProcessor在Spring容器中也是作为一个Bean存在的。在这个Bean初始化的过程中,就执行到invokeAwareMethods(beanName, bean);方法,此时就会到对应接口BeanClassLoaderAware的方法、

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

另外两个Aware接口也是在Bean实例化过程中回调的,只不过在BeanClassLoaderAware后面,如下图所示,一个是在图中1位置,一个是在图中2位置。
在这里插入图片描述
通过一个类型为ApplicationContextAwareProcessor的后置处理器来处理的。

private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}
}

那么此处有一个问题,这个ApplicationContextAwareProcessor是什么时候实例化的呢?难道还会在ConfigurationClassPostProcessor之前实例化?我们前面不都提到过,ConfigurationClassPostProcessor优先级比较高,而且在其他类型bean实例化之前就开始实例化并invoke调用了?在Spring容器中,BeanPostProcessor也是在BeanFactoryPostProcessor之后的。如下图所示:
在这里插入图片描述
但因为这个ApplicationContextAwareProcessor地位重要(任何bean都可能实现ApplicationContextAware接口),所示必须提前进行了初始化。如下图所示,ApplicationContextAwareProcessor是在1里面进行实例化的,而ConfigurationClassPostProcessor却要等到2里面进行实例化,而其他常规bean更要靠后才会初始化,所以这样才能达到实现了ApplicationContextAware接口的bean都能被设置ApplicationContext属性。

在这里插入图片描述
对应的源码如下所示:

/**
 * Configure the factory's standard context characteristics,
 * such as the context's ClassLoader and post-processors.
 * @param beanFactory the BeanFactory to configure
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	beanFactory.setBeanClassLoader(getClassLoader());
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	// 此处添加了一个后置处理器,当所有Bean初始化的过程中就会进行回调,一些Aware接口就回起作用
	// 直接new就可以了 Spring中的bean不一定都是反射的 也可以直接new出来 	
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register default environment beans.
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}

在这里,有很多一些重要的设置,除了这个ApplicationListenerDetector之外,还注册了一些单例,比如如下几个名称的单例bean。

String ENVIRONMENT_BEAN_NAME = "environment";
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

为什么我们能够自动注入ApplicationContext的,秘密就在上面。

执行逻辑

一 :从Configuration类中提取Bean定义

  1. 首先通过两个Set集合保证postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法还未执行,也就是说processConfigBeanDefinitions方法只能执行一次
private final Set<Integer> registriesPostProcessed = new HashSet<>();
private final Set<Integer> factoriesPostProcessed = new HashSet<>();
/**
 * Derive further bean definitions from the configuration classes in the registry.
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	// 使用hashCode作为注册ID 使用这个ID来判断当前这个后置处理有没有进行过postProcessBeanDefinitionRegistry方法和postProcessBeanFactory,如果已经执行过,就会抛出异常,也就是说这个Bean只执行一次,保证的注册的Bean的唯一性
	int registryId = System.identityHashCode(registry);
	// 保证postProcessBeanDefinitionRegistry方法还未执行
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	// 保证postProcessBeanFactory还未执行
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}
  1. 进行配置类型Bean的处理
/**
 * Build and validate a configuration model based on the registry of
 * {@link Configuration} classes.
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 获取已经注册的Bean定义名称
	String[] candidateNames = registry.getBeanDefinitionNames();

此时能获取到的Bean名称如下所示:前面5个是在容器创建的时候定义的。可以参考本人博客:https://blog.csdn.net/m0_37607945/article/details/106418334
在这里插入图片描述
第6个,是程序的主类,是在org.springframework.boot.SpringApplication#prepareContext方法中注册的,可以参考博客:https://blog.csdn.net/m0_37607945/article/details/106447591

1. CachingMetadataReaderFactoryPostProcessor

最后一个Bean呢?在Spring Boot的类Spring Application在run时,会进行prepareContext,然后执行ApplicationContextInitializer接口的实现类,而这些实现类是在SpringApplication对象过程中通过SPI机制从spring.factories中加载并实例化的。通过调用applyInitializers(context)方法对每个实现类执行initialize方法。源码如下

protected void applyInitializers(ConfigurableApplicationContext context) {
	for (ApplicationContextInitializer initializer : getInitializers()) {
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
				ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		initializer.initialize(context);
	}
}

这些实现类中有一个为SharedMetadataReaderFactoryContextInitializer,在执行这个类的initialize方法时会注入的一个BeanDefinitionRegistryPostProcessor.也就是CachingMetadataReaderFactoryPostProcessor.这个类也实现了BeanDefinitionRegistryPostProcessor接口和PriorityOrdered接口。也就是它注册了上面我们说的最后的那个bean,源码如下:

@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		register(registry);
		configureConfigurationClassPostProcessor(registry);
	}

	private void register(BeanDefinitionRegistry registry) {
		BeanDefinition definition = BeanDefinitionBuilder
				.genericBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)
				.getBeanDefinition();
		registry.registerBeanDefinition(BEAN_NAME, definition);
	}

并且order为Ordered.HIGHEST_PRECEDENCE。而ConfigurationClassPostProcessor的order是Ordered.LOWEST_PRECEDENCE, 道理来说,这两个Bean定义在注册后置处理器列表中ConfigurationClassPostProcessor应该在前面执行的。但是在看CachingMetadataReaderFactoryPostProcessor源码时竟然有如下的注释:
在这里插入图片描述
那这是为什么呢?另外这个类也与ConfigurationClassPostProcessor有一些关系(属性),如下所示:

public static final String BEAN_NAME = "org.springframework.boot.autoconfigure."
			+ "internalCachingMetadataReaderFactory"

private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
	try {
		BeanDefinition definition = registry
				.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
		definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
	}
	catch (NoSuchBeanDefinitionException ex) {
	}
}

在这里插入图片描述
下面我们来分析ConfigurationClassPostProcessorCachingMetadataReaderFactoryPostProcessor的执行先后问题。
在上面注册SharedMetadataReaderFactoryContextInitializer注册的时候我们忽视了一点,再看一下源码

applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());

直接实例化并添加到容器中的一个属性列表中,

/** BeanFactoryPostProcessors to apply on refresh. */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
	Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
	this.beanFactoryPostProcessors.add(postProcessor);
}

这个beanFactoryPostProcessors列表是Spring容器的一个属性。那ConfigurationClassPostProcessor呢?在构造容器时,进行注册,存放到beanDefinitionMap中的。然后在执行invokeBeanFactoryPostProcessors方法时首先处理beanFactoryPostProcessors,然后才是从容器中查找。
在这里插入图片描述
所以说,这二者并不是通过Order来比较先后执行顺序的。
遍历上面返回的所有的beanNames,其实也就就是遍历目前容器中已经定义的Bean定义了

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
				ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

2. 判断是否为目标类checkConfigurationClassCandidate

判断FullConfiguration还是LiteConfiguration(目标是那些会引入bean定义的类),full类型就是注解@configuration的类,而其他引入bean定义的方式(比如@Component)的则为lite类型。Spring容器在判断一次之后,会设置为对应beandefinition的属性值,这样下次就可以不用再才判断了(查找注解是通过反射来进行的,比较消耗资源)。所以下面的逻辑是首先判断对应beandefinition中是不是有这个属性,如果不存在,才会去查找。(类似于缓存

private static final String CONFIGURATION_CLASS_FULL = "full";

private static final String CONFIGURATION_CLASS_LITE = "lite";

private static final String CONFIGURATION_CLASS_ATTRIBUTE =
			Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
/**
 * Determine whether the given bean definition indicates a full {@code @Configuration}
 * class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
 */
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
	return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
/**
 * Determine whether the given bean definition indicates a lite {@code @Configuration}
 * class, through checking {@link #checkConfigurationClassCandidate}'s metadata marker.
 */
public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
	return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}

从ConfigurationClassPostProcessor中获取configurationClass属性值,看是否等于full或是lite。

/**
 * Return an attribute name qualified by the given enclosing {@link Class}.
 * For example the attribute name '{@code foo}' qualified by {@link Class}
 * '{@code com.myapp.SomeClass}' would be '{@code com.myapp.SomeClass.foo}'
 */
public static String getQualifiedAttributeName(Class<?> enclosingClass, String attributeName) {
	Assert.notNull(enclosingClass, "'enclosingClass' must not be null");
	Assert.notNull(attributeName, "'attributeName' must not be null");
	return enclosingClass.getName() + '.' + attributeName;
}

因此上面的属性名称应该是org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass,也就是说通过读取每一个上面获取到的bean定义,看看里面有没有定义这个属性,然后与full和lite进行比较。如果存在,则说明这个BeanDefinition已经被处理过了。
如果这些属性值为空,则检查当前bean定义是否是configuration类以及fulllite类型。源码如下:

/**
 * Check whether the given bean definition is a candidate for a configuration class
 * (or a nested component class declared within a configuration/component class,
 * to be auto-registered as well), and mark it accordingly.
 * @param beanDef the bean definition to check
 * @param metadataReaderFactory the current factory in use by the caller
 * @return whether the candidate qualifies as (any kind of) configuration class
 */
public static boolean checkConfigurationClassCandidate(
		BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
  1. 如果是工厂方法定义的Bean则不处理
	String className = beanDef.getBeanClassName();
	// 1 工厂方法定义的Bean不是配置类
	if (className == null || beanDef.getFactoryMethodName() != null) {
		return false;
	}
  1. 获取一个类的元数据,主要是通过MetadataReaderFactory来读取的
	// 解析类定义的元数据
	AnnotationMetadata metadata;
	if (beanDef instanceof AnnotatedBeanDefinition &&
			className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
		// Can reuse the pre-parsed metadata from the given BeanDefinition...
		metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
	}
	else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
		// Check already loaded Class if present...
		// since we possibly can't even load the class file for this Class.
		Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
		metadata = new StandardAnnotationMetadata(beanClass, true);
	}
	else {
		try {
			MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
			metadata = metadataReader.getAnnotationMetadata();
		}
		catch (IOException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Could not find class file for introspecting configuration annotations: " +
						className, ex);
			}
			return false;
		}
	}
  1. 根据元数据判断full或lite类型,如果是类上包含注解@Configuration则为full,如果是其他值(@Component、@ComponentScan、@Import、@ImportResource、),或者有方法上包含@Bean注解,都是lite,都是需要注册的类。
	if (isFullConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	else if (isLiteConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}

判断full或lite类型

/**
 * Check the given metadata for a full configuration class candidate
 * (i.e. a class annotated with {@code @Configuration}).
 * @param metadata the metadata of the annotated class
 * @return {@code true} if the given class is to be processed as a full
 * configuration class, including cross-method call interception
 */
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
	return metadata.isAnnotated(Configuration.class.getName());
}

private static final Set<String> candidateIndicators = new HashSet<>(8);

static {
	candidateIndicators.add(Component.class.getName());
	candidateIndicators.add(ComponentScan.class.getName());
	candidateIndicators.add(Import.class.getName());
	candidateIndicators.add(ImportResource.class.getName());
}

/**
 * Check the given metadata for a lite configuration class candidate
 * (e.g. a class annotated with {@code @Component} or just having
 * {@code @Import} declarations or {@code @Bean methods}).
 * @param metadata the metadata of the annotated class
 * @return {@code true} if the given class is to be processed as a lite
 * configuration class, just registering it and scanning it for {@code @Bean} methods
 */
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
	// Do not consider an interface or an annotation...
	if (metadata.isInterface()) {
		return false;
	}

	// Any of the typical annotations found?
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// Finally, let's look for @Bean methods...
	try {
		return metadata.hasAnnotatedMethods(Bean.class.getName());
	}
	catch (Throwable ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
		}
		return false;
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于AttributeAccessorSupport这个抽象类,几乎所有Bean定义类型都实现了这个抽象父类,方便设置bean的属性值。
在这里插入图片描述
4. 最后如果类上还有@Order注解,则会在bean定义中添加属性org.springframework.context.annotation.ConfigurationClassPostProcessor.order.

	// It's a full or lite configuration candidate... Let's determine the order value, if any.
	Integer order = getOrder(metadata);
	if (order != null) {
		beanDef.setAttribute(ORDER_ATTRIBUTE, order);
	}

	return true;
}

3. 针对目标集合排序

如果通过以上的方式判断出有full或者lite configuration的的class,首先会根据order进行排序

	// Return immediately if no @Configuration classes were found
	if (configCandidates.isEmpty()) {
		return;
	}

	// Sort by previously determined @Order value, if applicable
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});

4. 判断是否有自定义的BeanName生成策略

	// Detect any custom bean name generation strategy supplied through the enclosing application context
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

在这里插入图片描述

	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

5 ConfigurationClassParser解析并注册bean定义

主要涉及两个工具类:ConfigurationClassParserConfigurationClassBeanDefinitionReader
前者将BeanDefinitionHolder解析为Map<ConfigurationClass, ConfigurationClass>,(此过程不会注册任何bean)
后者将ConfigurationClass变成Set<Bedefinition>(真正注册的地方)

  1. 通过ConfigurationClassParser解析然后存放到configurationClassesMap属性当中,此过程不会注册任何bean,参考博客:ConfigurationClassParser解析@Configuration类源码详解
  2. 进行验证,然后移除缓存中已经处理过的ConfigurationClass
  3. 通过ConfigurationClassBeanDefinitionReader加载configurationClasses的bean定义(loadBeanDefinitions),参考博客:@Configuration注册器ConfigurationClassBeanDefinitionReader,然后添加缓存
  4. 在目前已经注册过的所有bean中,找出尚未进行处理的ConfigurationClass类型的bean(一般情况不会有),重复以上步骤
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
	parser.parse(candidates);
	parser.validate();

	Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
	configClasses.removeAll(alreadyParsed);

	// Read the model and create bean definitions based on its content
	if (this.reader == null) {
		this.reader = new ConfigurationClassBeanDefinitionReader(
				registry, this.sourceExtractor, this.resourceLoader, this.environment,
				this.importBeanNameGenerator, parser.getImportRegistry());
	}
	this.reader.loadBeanDefinitions(configClasses);
	alreadyParsed.addAll(configClasses);

	candidates.clear();
	if (registry.getBeanDefinitionCount() > candidateNames.length) {
	    // 获取所有已经注册的类名称
		String[] newCandidateNames = registry.getBeanDefinitionNames();
		// 在processConfigBeanDefinitions之前就已经存在的beanNames
		Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
		Set<String> alreadyParsedClasses = new HashSet<>();
		for (ConfigurationClass configurationClass : alreadyParsed) {
			// 已经处理过的ConfigurationClass
			alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
		}
		for (String candidateName : newCandidateNames) {
			if (!oldCandidateNames.contains(candidateName)) {
				BeanDefinition bd = registry.getBeanDefinition(candidateName);
				// 没有处理过的ConfigurationClass继续进行处理
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
						!alreadyParsedClasses.contains(bd.getBeanClassName())) {
					candidates.add(new BeanDefinitionHolder(bd, candidateName));
				}
			}
		}
		candidateNames = newCandidateNames;
	}
}
while (!candidates.isEmpty());

通过该步骤,解析Java配置的bean定义并注册到容器当中

6. 注册额外bean以及清空元数据缓存

	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}

	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
		// Clear cache in externally provided MetadataReaderFactory; this is a no-op
		// for a shared cache since it'll be cleared by the ApplicationContext.
		((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
	}

二 :对Configuration类进行增强操作(代理)

通过postProcessBeanDefinitionRegistry操作完成了bean定义的注册操作。
接下来需要针对部分bean进行增强操作。
这部分的逻辑是在postProcessBeanFactory方法中实现的。执行时机在在处理完所有BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry方法之后。具体参考PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法。

/**
 * Prepare the Configuration classes for servicing bean requests at runtime
 * by replacing them with CGLIB-enhanced subclasses.
 */
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	int factoryId = System.identityHashCode(beanFactory);
	if (this.factoriesPostProcessed.contains(factoryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
	}
	this.factoriesPostProcessed.add(factoryId);
	if (!this.registriesPostProcessed.contains(factoryId)) {
		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
		// Simply call processConfigurationClasses lazily at this point then.
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}
    // 进行ConfigurationClasses的增强操作
	enhanceConfigurationClasses(beanFactory);
	// 添加一个bean后置处理器
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

1. 进行ConfigurationClasses的增强操作

在BeanFactory中查找Configuration类型的bean定义

/**
 * Post-processes a BeanFactory in search of Configuration class BeanDefinitions;
 * any candidates are then enhanced by a {@link ConfigurationClassEnhancer}.
 * Candidate status is determined by BeanDefinition attribute metadata.
 * @see ConfigurationClassEnhancer
 */
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
			if (!(beanDef instanceof AbstractBeanDefinition)) {
				throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
						beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
			}
			else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
				logger.info("Cannot enhance @Configuration bean definition '" + beanName +
						"' since its singleton instance has been created too early. The typical cause " +
						"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
						"return type: Consider declaring such methods as 'static'.");
			}
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	if (configBeanDefs.isEmpty()) {
		// nothing to enhance -> return immediately
		return;
	}

通过ConfigurationClassEnhancer进行增强

	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
		AbstractBeanDefinition beanDef = entry.getValue();
		// If a @Configuration class gets proxied, always proxy the target class
		beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		try {
			// Set enhanced subclass of the user-specified bean class
			Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
			if (configClass != null) {
				Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
				if (configClass != enhancedClass) {
					if (logger.isTraceEnabled()) {
						logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
								"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
					}
					beanDef.setBeanClass(enhancedClass);
				}
			}
		}
		catch (Throwable ex) {
			throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
		}
	}
}

所谓的CGLIB增强,无非就是执行对应的回调方法,在ConfigurationClassEnhancer中添加了三个Callback实现类

// The callbacks to use. Note that these callbacks must be stateless.
private static final Callback[] CALLBACKS = new Callback[] {
		new BeanMethodInterceptor(),
		new BeanFactoryAwareMethodInterceptor(),
		NoOp.INSTANCE
};

最后一个是空实现,前两个额外实现了另外两个接口MethodInterceptorConditionalCallback,分别对应回调方法和条件判断。

第一个用于处理加了@Scope注解的@Bean方法。
在这里插入图片描述
2. 添加ImportAwareBeanPostProcessor后置处理器

beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

通过以上增强之后,每个ConfigurationClass(full mode)都是EnhancedConfiguration类型对象,因此在实例化的过程中都会被ImportAwareBeanPostProcessor进行后置处理,设置beanFactory。对应方法如下:

@Override
public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
	// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
	// postProcessProperties method attempts to autowire other configuration beans.
	if (bean instanceof EnhancedConfiguration) {
		((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
	}
	return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
	if (bean instanceof ImportAware) {
		ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
		AnnotationMetadata importingClass = ir.getImportingClassFor(bean.getClass().getSuperclass().getName());
		if (importingClass != null) {
			((ImportAware) bean).setImportMetadata(importingClass);
		}
	}
	return bean;
}

之所以需要进行增强,主要是在通过java方法注册Bean的时候会存在依赖或者FactoryBean的情形,此时通过BeanMethodInterceptor来进行拦截并相应处理,具体可以参考博客:
@Bean注册Bean,你有多了解?

在这里插入图片描述

总结

ConfigurationClassPostProcessor作为Spring中最重要的后置处理器,一点也不为过。

  1. 作为BeanDefinitionRegistryPostProcessor,在postProcessBeanDefinitionRegistry方法中完成了解析(BeanDefinitionHolder->ConfigurationClass)和注册(ConfigurationClass->BeanDefinition)两个动作,这其中通过各种数据结构(LinkedHashSet、LinkedHashMap,甚至提供了DeferredImportSelector接口),当然Spring或Spring Boot为了保证顺序性不只这些,还有@Order@AutoConfigureOrder等。
  2. 作为BeanFactoryPostProcessor,在postProcessBeanFactory方法中增对带有注解@Configuration注解的bean进行了增强,为什么要进行增强,因为我们通常都是在这些类中去定义需要进行注册的Bean对象的,获取实例的方式就是去反射调用对应的方法,但是方法引用设置其他的bean,必须要保证单例,调用FactoryBean类型的时候,要返回getObject对象,这一块需要结合整个Spring来说才有意义了。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值