【spring】配置类解析整体流程

配置类解析与扫描简单介绍

  • 本文源码基于spring-framework-5.3.10。
  • 源码入口:org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)
  • 调用位置:spring启动的时候会执行BeanFactoryPostProcessor重写的方法的时候。

FULL配置类与LITE配置类

  • FULL配置类:存在@Configuration(proxyBeanMethods = false)的时候。
  • LITE配置类:除了proxyBeanMethods = false的时候,只要加了@Configuration就是配置类;不加@Configuration,存在@Component、@ComponentScan、@Import、@ImportResource四种的一个,或者存在@Bean注解了的方法也是配置类。
  • 除了上述的俩种类型,其余的类对于spring来说都不是配置类。

解析配置类整体思路

  • 配置类上是否存在@Component、检查内部类是不是配置类、解析该新配置类。
  • 配置类上是否有@ComponentScan、扫描并注册BeanDefinition、检查是否存在配置类、解析该新配置类。
  • 配置类上是否有@Import、调用processImports()处理所导入的类、是ImportSelector类型、是DeferredImportSelector类型、表示推迟的ImportSelector,它会在当前配置类所属的批次中所有配置类都解析完了之后执行。
  • 配置类上是否有@Import、调用processImports()处理所导入的类、是ImportSelector类型、是普通ImportSelector类型、把selectImports()方法所返回的类再次调用processImports()进行处理。
  • 配置类上是否有@Import、调用processImports()处理所导入的类、是ImportBeanDefinitionRegistrar类型、将ImportBeanDefinitionRegistrar实例对象添加到当前配置类的importBeanDefinitionRegistrars属性中。
  • 配置类上是否有@Import、调用processImports()处理所导入的类、是普通类型、当作新配置类进行解析
  • 配置类上是否有@ImportResource、将所导入的xml文件路径添加到当前配置类的importedResources属性中。
  • 配置类中是否有@Bean、将@Bean修饰的方法封装为BeanMethod对象,并添加到当前配置类的beanMethods属性中。
  • 配置类所实现的接口中是否有@Bean、将@Bean修饰的方法封装为BeanMethod对象,并添加到当前配置类的beanMethods属性中
  • 把配置类的父类当作配置类进行解析

源码分析

/**
 * 一个实现了BeanDefinitionRegistryPostProcessor的子类
 */
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	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);

	// 解析配置类
	processConfigBeanDefinitions(registry);
}

获取配置类的过程:processConfigBeanDefinitions源码分析

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	// 得到所有的BeanDefinition名称,首次这里只能拿到传入的配置类、以及一些系统默认的BeanDefinition。
	// 比如首次可以拿到:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、ConfigurationClassPostProcessor、自己传入的配置类...
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			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));
		}
	}

	// Return immediately if no @Configuration classes were found
	// 配置类不存在,直接返回!
	if (configCandidates.isEmpty()) {
		return;
	}

	// Sort by previously determined @Order value, if applicable
	// 通过@Order可以排序,升序排序,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
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			// 可以预先往单例池中添加一个CONFIGURATION_BEAN_NAME_GENERATOR的BeanNameGenerator类型的bean
			// 可以用来作为扫描得到的Bean和import导入进来的Bean的beanName
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

	// 配置环境变量的为null,初始化一个
	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// Parse each @Configuration class
	// 构建一个配置类的解析器
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());

	// 递归解析配置类,有可能通过解析一个配置类,得到了其他的配置类,比如扫描和Importt
	do {
		StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");

		// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass
		// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass
		// 解析配置类的结果是什么?
		parser.parse(candidates);  // AppConfig.class--->BeanDefinition
		parser.validate();

		// configClasses相当于就是解析之后的结果
		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());
		}
		// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition
		// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResource
		this.reader.loadBeanDefinitions(configClasses);

		alreadyParsed.addAll(configClasses);
		processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

		// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClass
		candidates.clear();

		// 如果发现BeanDefinition增加了,则有可能增加了配置类
		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);

					// 检查多出来的BeanDefinition是不是配置类,需不需要解析
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());

	// 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();
	}
}

什么样的类是配置类:checkConfigurationClassCandidate源码分析

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

	// @Bean定义的配置类Bean是不起作用的
	String className = beanDef.getBeanClassName();
	if (className == null || beanDef.getFactoryMethodName() != null) {
		return false;
	}

	// AnnotationMetadata表示某个类的注解信息,但是并一定要加载这个类
	AnnotationMetadata metadata;

	// 如果AnnotatedBeanDefinition,则直接取AnnotationMetadata
	if (beanDef instanceof AnnotatedBeanDefinition &&
			className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
		// Can reuse the pre-parsed metadata from the given BeanDefinition...
		metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
	}
	// 如果是AbstractBeanDefinition,则解析beanClass得到AnnotationMetadata
	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();
		if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
				BeanPostProcessor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
				EventListenerFactory.class.isAssignableFrom(beanClass)) {
			return false;
		}
		metadata = AnnotationMetadata.introspect(beanClass);
	}
	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;
		}
	}

	// 得到当前类上加了@Configuration的注解信息
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());

	// 存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类,直接翻译是满的
	// 这里主要处理@Configuration(proxyBeanMethods = false)的逻辑。默认当前属性为true
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	// 存在@Configuration,并且proxyBeanMethods为false时,是lite配置类,直接翻译是轻的
	// 或者不存在@Configuration,但是只要存在@Component、@ComponentScan、@Import、@ImportResource四个中的一个,就是lite配置类
	// 或者不存在@Configuration,只要存在@Bean注解了的方法,就是lite配置类
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		return false;
	}

	// 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;
}

解析配置类:parse源码分析

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	// 遍历每个配置类
	for (BeanDefinitionHolder holder : configCandidates) {
		// 得到配置类对应的BeanDefinition
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			// 解析BeanDefinition所对应的类
			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);
		}
	}

	// 处理deferredImportSelectors,表示当前所有配置类解析完了之后才执行
	// deferredImportSelector表示推迟的ImportSelector,正常的ImportSelector是在解析配置类的过程中执行的
	this.deferredImportSelectorHandler.process();
}

/**
 * 解析之前的封装
 */
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
	// 把类的元信息和beanName封装为ConfigurationClass
	processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

/**
 * 配置类处理的方法
 */
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) 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()) {
			// 重复导入:OrderService导入了AccountService,UserService也导入了AccountService,就会符合这个条件
			// 当前配置类有@Import,之前解析过,不解析!
			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.
			// 当前配置类没有@Import,覆盖之前的
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}

	// Recursively process the configuration class and its superclass hierarchy.
	SourceClass sourceClass = asSourceClass(configClass, filter);
	// 这个循环是找到这个配置类的所有父类进行解析!
	do {
		// 真正解析配置类的核心方法
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);

	// ConfigurationClass重写了equals方法,只要两个ConfigurationClass对应的className相等就可以
	this.configurationClasses.put(configClass, configClass);
}

/**
 * 真正解析配置类的核心方法
 */
protected final SourceClass doProcessConfigurationClass(
		ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
		throws IOException {

	// 当前类上存在@Component注解!
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		// 处理内部类
		// 在解析一个配置类时,如果类上有@Component,则会判断内部类是不是lite配置类并进行解析,并且会记录为被导入的
		processMemberClasses(configClass, sourceClass, filter);
	}

	// Process any @PropertySource annotations
	// 这里处理@PropertySource注解。读取配置文件,放入environment中
	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");
		}
	}

	// Process any @ComponentScan annotations
	// 会进行扫描,得到的BeanDefinition会注册到Spring容器中,并且会检查是不是配置类并进行解析
	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) {
			// The config class is annotated with @ComponentScan -> perform the scan immediately
			// 这里就会进行扫描,得到的BeanDefinition会注册到Spring容器中
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
			// 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();
				}
				// 检查扫描出来的BeanDefinition是不是配置类(full和lite)
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	// Process any @Import annotations
	// getImports(sourceClass)会拿到@Import导入的类
	// 如果导入的是普通类,那么会直接把它当做配置类来解析
	// 如果导入的是普通ImportSelector,那么会将返回的类再次调用processImports()
	// 如果导入的是特殊ImportSelector,DeferredImportSelector,那么暂时不会处理,会在解析完所有当前这轮配置类后进行导入,将返回的类再次调用processImports()
	// 如果导入的是ImportBeanDefinitionRegistrar,那么暂时不会处理,会在解析完所有当前这轮配置类后,将配置类解析成为BeanDefinition之后进行调用
	processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

	// 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);
		}
	}

	// Process individual @Bean methods
	// 解析配置类中的@Bean,但并没有真正处理@Bean,只是暂时找出来
	Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
	for (MethodMetadata methodMetadata : beanMethods) {
		configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
	}

	// Process default methods on interfaces
	// 解析配置类所实现的接口中的@Bean,但并没有真正处理@Bean,只是暂时找出来
	processInterfaces(configClass, sourceClass);

	// 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;
}

/**
 * 内部类的处理
 */
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
		Predicate<String> filter) throws IOException {

	// 得到所有的内部类
	Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
	if (!memberClasses.isEmpty()) {
		List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
		for (SourceClass memberClass : memberClasses) {
			// 内部类是不是lite配置类
			if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
					!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
				candidates.add(memberClass);
			}
		}

		// 排序
		OrderComparator.sort(candidates);


		for (SourceClass candidate : candidates) {
			// AppConfig中有一个内部类A, A上用@Import导入AppConfig.class,就出现了循环import
			if (this.importStack.contains(configClass)) {
				// 就是直接抛异常
				this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
			}
			else {
				this.importStack.push(configClass);
				try {
					// 配置类进行处理
					processConfigurationClass(candidate.asConfigClass(configClass), filter);
				}
				finally {
					this.importStack.pop();
				}
			}
		}
	}
}

结束语

  • 获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
  • 关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!
  • 关注公众号,后续持续高效的学习JVM!
  • 这个公众号,无广告!!!每日更新!!!
    作者公众号.jpg
posted @ 2022-03-01 20:59  程序java圈  阅读(197)  评论(0编辑  收藏  举报