spring 源码系列(五)ConfigurationClassPostProcessor源码解析

目录

一、继承关系

二、时序图

三、源码解析

postProcessBeanDefinitionRegistry()

2.1 获取到BeanDefinition列表,取出所有未解析过的BeanDefinition.

2.2 排序

2.3 解析bean

2.4 将读取到configClasses加载到容器中,即beanDefinitionMap

postProcessBeanFactory()

1. 对@Configuration标注的bean进行动态代理。

2. 添加一个后置处理器,用于给被cglib动态代理的bean注入BeanFactory


 

spring初始化过程中添加了很多spring自身创建的bean,其中最重要的就是ConfigurationClassPostProcessor,它完成了spring对于bean的扫描,以及配置类的代理。

一、继承关系

spring 源码系列(五)ConfigurationClassPostProcessor源码解析_第1张图片

可以看到ConfigurationClassPostProcessor实现的接口总共有三个源头:

1)Ordered ,这个接口的实现,是用来排序的

2)Aware 下的接口实现,主要是配置一些spring环境

3)BeanFactoryPostProcessor 这个接口就是ConfigurationClassPostProcessor的核心了,它完成了spring的扫描工作

前文已经介绍过BeanFactoryPostProcessor是一个工厂后置处理器,可以借助BeanFactory和BeanDefinitionRegistry(BeanDefinitionRegistryPostProcessor)完成一些操作

二、时序图

spring 源码系列(五)ConfigurationClassPostProcessor源码解析_第2张图片

三、源码解析

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口提供有两个方法,postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)postProcessBeanFactory(ConfigurableListableBeanFactory)。spring会先执行postProcessBeanDefinitionRegistry(),那么就先从postProcessBeanDefinitionRegistry()分析。

postProcessBeanDefinitionRegistry()

postProcessBeanDefinitionRegistry()方法传入了BeanDefinitionRegistry 即注册器,spring扫描完成就是借助BeanDefinitionRegistry。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	//获取hash code
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	//执行bean 解析
	processConfigBeanDefinitions(registry);
}

1. 获取一个registryId,添加到registriesPostProcessed中,这里只是做一个标记,标记该方法执行过。

2. 解析bean

List configCandidates = new ArrayList<>();
//从registry(factory)中获得所有BeanDefinitionNames
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
	BeanDefinition beanDef = registry.getBeanDefinition(beanName);
	//判断是否已经执行过,"full"和 "lite"都是标志
	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));
	}
}

if (configCandidates.isEmpty()) {
	return;
}

//这里会排序,根据Order
configCandidates.sort((bd1, bd2) -> {
	int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
	int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
	return Integer.compare(i1, i2);
});

.....代码省略......

//创建ConfigurationClassParser,用于解析Bean
ConfigurationClassParser parser = new ConfigurationClassParser(
		this.metadataReaderFactory, this.problemReporter, this.environment,
		this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
	//解析这个bean
	parser.parse(candidates);
	parser.validate();

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

	//创建一个reader
	if (this.reader == null) {
		this.reader = new ConfigurationClassBeanDefinitionReader(
				registry, this.sourceExtractor, this.resourceLoader, this.environment,
				this.importBeanNameGenerator, parser.getImportRegistry());
	}
	//将读取到configClasses加载到容器中,即beanDefinitionMap
	this.reader.loadBeanDefinitions(configClasses);
	//将configClasses加入到已经处理过的set中
	alreadyParsed.addAll(configClasses);
	candidates.clear();
	
	.....代码省略......
}
while (!candidates.isEmpty());
.....代码省略......

2.1 获取到BeanDefinition列表,取出所有未解析过的BeanDefinition.

判断是否有full或者lite标注,如果有,则证明已经解析过了

如果没有则未被解析,加入到集合configCandidates中

2.2 排序

2.3 解析bean

  • parser.parse(candidates)

parser.parse(candidates)方法调用流程 :

//判断这个类有没有被别的@Import
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
	if (configClass.isImported()) {
		if (existingClass.isImported()) {
			existingClass.mergeImportedBy(configClass);
		}
		return;
	}
	else {
		this.configurationClasses.remove(configClass);
		this.knownSuperclasses.values().removeIf(configClass::equals);
	}
}

// 处理配置类,由于配置类可能存在父类(若父类的全类名是以java开头的,则除外),所有需要将configClass变成sourceClass去解析,
// 然后返回sourceClass的父类。
// 如果此时父类为空,则不会进行while循环去解析,如果父类不为空,则会循环的去解析父类
// SourceClass的意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
// 如果无法理解,可以把它当做一个黑盒,不会影响看spring源码的主流程
SourceClass sourceClass = asSourceClass(configClass);
do {
	sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);

这里会将configClass处理成SourceClass,其实就是一个数据转存的过程。值得注意的是,最后那个do循环中会对继承关系进行处理。

它的核心代码是doProcessConfigurationClass(configClass, sourceClass)

  • doProcessConfigurationClass(configClass, sourceClass)
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		//递归处理内部类
		processMemberClasses(configClass, sourceClass);
	}

	// 处理 @PropertySource注解,注入的属性
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		else {
			logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
					"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}

	//这里就是处理@ComponentScan扫描类了
	//获取到@ComponentScan中属性的值
	Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		for (AnnotationAttributes componentScan : componentScans) {
			//解析扫描包  最终委托给了componentScanParser去完成这件事
			Set scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			//检查扫描的定义集是否有其他配置类,并在需要时递归解析
			//就是扫描的包中如果有其他的配置类,那么就去解析这个配置类,并且查看是否定义了@ComponentScan注解
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {

				//这里是解析BeanDefinitionHolder,查看其中是否有配置类
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					//这里会再次去解析这个配置类
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	//处理 @Import注解
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	//处理@ImportResource注解引入的配置文件
	AnnotationAttributes importResource =
			AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	if (importResource != null) {
		String[] resources = importResource.getStringArray("locations");
		Class readerClass = importResource.getClass("reader");
		for (String resource : resources) {
			String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
			configClass.addImportedResource(resolvedResource, readerClass);
		}
	}

	//处理 @Bean 方法
	Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	//处理接口上的默认方法
	processInterfaces(configClass, sourceClass);
	//判断是否还有父类
	if (sourceClass.getMetadata().hasSuperClass()) {
		String superclass = sourceClass.getMetadata().getSuperClassName();
		if (superclass != null && !superclass.startsWith("java") &&
				!this.knownSuperclasses.containsKey(superclass)) {
			this.knownSuperclasses.put(superclass, configClass);
			return sourceClass.getSuperClass();
		}
	}

	return null;
}

1)判断是否有内部类,有则递归调用处理内部类

2)处理 @PropertySource注解 这个属性注入

3)处理@ComponentScan 

如果为空,说明此bean只是一个普通的bean,直接跳过该步骤

如果不为空,则说明该bean是一个配置类,读取出@ComponentScan 注解中的配置

        委托给componentScanParser进行解析(放在下一篇中解析

        ConfigurationClassUtils.checkConfigurationClassCandidate()判断扫描出来的bean是否含有配置类。如有则递归解析

4)处理 @Import注解  (放在下一篇中解析

5)处理@ImportResource注解引入的配置文件

6)处理 @Bean 方法

7)判断是否还有父类,如果有则返回,进行循环处理

  • ConfigurationClassUtils.checkConfigurationClassCandidate()
public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

	//.....省略部分代码
	
	/**
	 * 判断是否加了@Configuration注解,添加了@Configuration注解的bean会被添加一个full标记,
	 * 会在ConfigurationClassPostProcessor#postProcessBeanFactory()中被使用cglib动态代理增强,通过cglib动态代理实现
	 * 使用@Configuration注解的bean中的  @Bean方法只会被调用一次(包含直接调用@Bean方法),即单例。
	 * @see ConfigurationClassPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
	 * @reviewer wangcongming
	 */
	if (isFullConfigurationCandidate(metadata)) {
		//如果加了@Configuration注解,则给beanDef加一个full标识
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	else if (isLiteConfigurationCandidate(metadata)) {
		//给beanDef加一个lite标识
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}
	//.....省略部分代码
}


public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
	//1. 判断是否是接口
	if (metadata.isInterface()) {
		return false;
	}

	/**
	 * 2. 判断是否加了以下注解
	 * Component ComponentScan Import ImportResource
	 * @reviewer wangcongming
	 */
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// 3. 查找加了@bean注解的方法
	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;
	}
}

这段源码可以看出以下几点:

1)被@Configuration标记的bean,会被标记为“full”,被@Component、@ComponentScan、@Import、@ImportResource标记的则会被标记为“lite” ,如果没有加以上注解,则会直接跳过该bean

2)@Import @ComponentScan @ImportResource或者类中有@Bean的方法的bean,没有使用@Configuration注解,也会被spring解析

2.4 将读取到configClasses加载到容器中,即beanDefinitionMap

this.reader.loadBeanDefinitions(configClasses);

这一行代码就是将@Import导入的bean加载为BeanDefinition(具体解析放在下一篇

 

postProcessBeanFactory()

在这里postProcessBeanFactory()方法主要是对@Configuration标注的bean进行代理。

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//......省略部分代码

	/**
	 * 对@Configuration标注的类中的@Bean方法进行cglib动态代理
	 * 为什么要动态代理呢?
	 * spring中的bean未被标注时,应该都是单例的,但是如果直接调用@Bean的方法创建对象,就会出现多例,与实际情况不符
	 * 此时可以采用动态代理来解决
	 * @reviewer wangcongming
	 */
	enhanceConfigurationClasses(beanFactory);
	//这里会添加一个后置处理器,用于给被cglib动态代理的bean注入BeanFactory
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

1. 对@Configuration标注的bean进行动态代理。

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {

	//将使用full标记的BeanDefinition存入configBeanDefs
	Map configBeanDefs = new LinkedHashMap<>();
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		//是否使用full标记
		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
			//......省略部分代码
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	//......省略部分代码

	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry entry : configBeanDefs.entrySet()) {
		AbstractBeanDefinition beanDef = entry.getValue();
		beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		try {
			Class configClass = beanDef.resolveBeanClass(this.beanClassLoader);
			if (configClass != null) {
				//调用ConfigurationClassEnhancer.enhance()方法创建增强类  这时返回的class是经过cglib动态代理后的class
				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);
		}
	}
}

Class enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);这里就是生成代理对象。

这里使用的是cglib动态代理,为什么不使用jdk动态代理,这是因为jdk动态代理是基于接口的

private Enhancer newEnhancer(Class configSuperClass, @Nullable ClassLoader classLoader) {
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(configSuperClass);
	//给新创建的代理对象添加一个接口EnhancedConfiguration
	/**
	 * @see ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor
	 */
	enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});
	enhancer.setUseFactory(false);
	enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
	//设置生成代理class的策略
	enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
	/**
	 * 添加了两个MethodInterceptor。(BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor)
	 * 通过这两个类的名称,可以猜出,前者是对加了@Bean注解的方法进行增强,后者是为代理对象的beanFactory属性进行增强
	 * 被代理的对象,如何对方法进行增强呢?就是通过MethodInterceptor拦截器实现的
	 * 类似于拦截器,每次执行请求时,都会对经过拦截器。
	 * 同样,加了MethodInterceptor,那么在每次代理对象的方法时,都会先经过MethodInterceptor中的方法
	 * @reviewer wangcongming
	 */
	enhancer.setCallbackFilter(CALLBACK_FILTER);
	enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
	return enhancer;
}

1)给代理类设置一个接口EnhancedConfiguration

添加EnhancedConfiguration接口,是因为会set一个BeanFactory,通过BeanFactory可以取出已经实例化的bean。

2)设置代理class生成策略

3)添加CallbackFilter

private static final Callback[] CALLBACKS = new Callback[] {
			new BeanMethodInterceptor(),
			new BeanFactoryAwareMethodInterceptor(),
			NoOp.INSTANCE
};

可以看出这里是添加了两个Callback
       BeanMethodInterceptor,功能是判断@Bean标注的方法创建的对象是否已经添加到BeanFactory中,如果有则直接取出返回,没有则创建。这就保证了Bean示例的单例性

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
					MethodProxy cglibMethodProxy) throws Throwable {

	//......省略部分代码
	//这里就是查看beanFactory中是否有该@Bean方法创建的对象,如果有则直接返回,没有则创建
	if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
			factoryContainsBean(beanFactory, beanName)) {
		Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
		if (factoryBean instanceof ScopedProxyFactoryBean) {
		}else {
			return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
		}
	}

	if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
		if (logger.isInfoEnabled() &&
				BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
							"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
							"result in a failure to process annotations such as @Autowired, " +
							"@Resource and @PostConstruct within the method's declaring " +
							"@Configuration class. Add the 'static' modifier to this method to avoid " +
							"these container lifecycle issues; see @Bean javadoc for complete details.",
					beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
		}
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}

	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

BeanFactoryAwareMethodInterceptor 功能是给代理对象添加一个BeanFactory属性

2. 添加一个后置处理器,用于给被cglib动态代理的bean注入BeanFactory

beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

众所周知,后置处理器会在bean初始化完成之后调用,调用ImportAwareBeanPostProcessor后置处理器,会给被cglib动态代理的配置类注入一个BeanFactory(通过EnhancedConfiguration接口的setBeanFactory()注入)。

 

你可能感兴趣的:(spring源码)