spring5源码阅读(七)ConfigurationClassPostProcessor作用及源码分析

此类是一个后置工厂处理器,比较核心重要,主要用于处理@Configuration注解修饰的类。
类图如下:
在这里插入图片描述
在前序文章《spring5源码阅读(五)Post Processors类型及作用详解》中的第一节,曾简单描述过此类的作用,可以那篇文章看起;本就其执行过程,再详细分析一下。
此类实现了BeanDefinitionRegistryPostProcessor接口,最终实现了BeanFactoryPostProcessor接口。
下面详细分析下实现的两个接口方法;

1. postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)

/**
 * Derive further bean definitions from the configuration classes in the registry.
 * 从注册表中的配置类,派生进一步的bean定义
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	//理论上启动过程中只会执行一次,这个if进不去
	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);
	//核心逻辑再这里
	processConfigBeanDefinitions(registry);
}

继续打开核心逻辑代码,这方法名字上就能看出,是解析配置类的bean定义,经过这个方法,@Configuration注解修饰的配置类上的所有其他注解,都会被解析,比如@ComponentScan,因此经过这个方法,我们自定义的bean(被@Component等注解修饰的)都会被扫描到并进行注册。

代码比较长,注意看代码注释:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		//存放@Configuration修饰的类
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//得到所有已经注册的bean名字
		//到这里一般只有那6个post process和我们自定义的config类
		String[] candidateNames = registry.getBeanDefinitionNames();

		//1.遍历查找@Configuration修饰的类,走到这里,只会有一个appConfig复合条件,因为其他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);
				}
			}
			//这里才设置了full和lite属性,所以即使一个bean上有@Configuration注解,也不能进入上边的判断
			//能进入上边的if判断,说明bean已经被处理过了
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

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

		// Sort by previously determined @Order value, if applicable
		//2.根据order大小排序,越小优先级越高,也就是升序排列
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context
		//检测自定义bean名称生成策略
		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();
		}

		//3. Parse each @Configuration class
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		//存放configCandidates的备份,临时变量,
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		//已经parse处理的Configuration类
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			//经过这一步,我们在项目中定义的@Componet/@Repository等,都会被注册bean定义
			//因为这一步解析了Configuration类型类的各种注解,比如@ComponentScan
			//这一步也有可能产生新的config类,因为Configuration类上可以使用@import注解导入他的配置类
			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());
			}
			//此方法中处理了@Import注解中的ImportBeanDefinitionRegistrar
			//这里可能会注册代理bean,比如AnnotationAwareAspectJAutoProxyCreator
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			//candidates parse完了,清空
			candidates.clear();

			//上边parse了config类型的类后,可能产生新的bean定义注册
			//所以这里很可能是大于candidateNames.length的
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							//走到这说明经过上面的parse方法,产生了新的Configuration类
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		//如果又有新的candidates出现,则继续循环
		while (!candidates.isEmpty());

		//将ImportRegistry注册为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修饰的类,走到这里,只会有一个appConfig复合条件,因为其他bean都还没注册;
  • 按照@Order执行顺序排序
  • 遍历解析各个@Configuration注解修饰的类,遍历结束后,还要判断是否产生了新的配置类,如果有的话,还要循环解析,直到不在有新的配置类产生;

上面这么长的代码,其实核心的代码就是如下方法:
ConfigurationClassParser#parse(candidates)

跟进去ConfigurationClassParser#parse(candidates)

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		this.deferredImportSelectors = new LinkedList<>();

		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					//这里进入
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		processDeferredImportSelectors();
	}

进入parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
		processConfigurationClass(new ConfigurationClass(metadata, beanName));
	}

继续进入processConfigurationClass()如下:

//处理@Configuration修饰的类
	protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		//根据@Conditional注解情况判断是否跳过
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			} else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		//递归处理configuration class和其父类,得到类上所有注解
		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass);
		do {
			//关键这一步解析各种注解
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
		this.configurationClasses.put(configClass, configClass);
	}

上面方法中由个关键方法doProcessConfigurationClass(configClass, sourceClass) 如下:

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

		// Recursively process any member (nested) classes first
		//递归处理内部类
		processMemberClasses(configClass, sourceClass);

		// Process any @PropertySource annotations
		//1. 处理@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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
		//2. 处理@ComponentScan
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				//立即扫描@ComponentScan配置的包路径
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				//遍历检查每一个扫描到的bean,是否又有@Configuration注解,有的话要递归解析其配置信息
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						//递归处理
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// 3. Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		//4. Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		//5. Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		//6. Process default methods on interfaces
		//接口中的默认方法
		processInterfaces(configClass, sourceClass);

		//7. Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}
		// No superclass -> processing is complete
		return null;
	}

此方法处理了@Configuration注解修饰的类,也就是依次获取以下注解内容并进行解析(如果由的话):@PropertySource/@ComponentScan/@Import /@ImportResource/@Bean 等注解 ,如果这些注解又引入了此类注解,那么就进行递归处理。比如@Import注解可能导入其他@configuration配置类。

2. postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

上面执行完postProcessBeanDefinitionRegistry方法后,
因为ConfigurationClassPostProcessor类也实现了BeanFactoryPostProcessor接口,这里看下具体的实现内容。

@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);
		}
        //增强Configuration类
		enhanceConfigurationClasses(beanFactory);
		//往容器中增加了一个ImportAwareBeanPostProcessor实例对象
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

该方法在bean定义注册结束后,bean实例化之前执行。
该方法主要做了两件事情:

  • enhanceConfigurationClasses(beanFactory) 使用cglib动态代理增强了Configuration
  • 往容器中增加了一个ImportAwareBeanPostProcessor实例对象

针对第一个,我们展开看下:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			//找到@Configuation注解修饰的配置类
			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.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
					logger.warn("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 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
			//preserveTargetClass设置为true,表示开启cglib动态代理
			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.isDebugEnabled()) {
							logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " +
									"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
						}
						//修改bean的class为代理类
						beanDef.setBeanClass(enhancedClass);
					}
				}
			} catch (Throwable ex) {
				throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
			}
		}
	}
  • 首先找到所有@Configuration修饰的配置类
  • 遍历每个配置类,使用ConfigurationClassEnhancer工具类进行增强;也就是使用cglib动态代理,产生代理子类,用于处理配置类中@Bean注解修饰的方法,实现在配置类中实例化对象效果。
发布了62 篇原创文章 · 获赞 29 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csdn_20150804/article/details/102665709