Spring配置类以及扫描过程源码解析

书接上文

文章目录

    • 一、 拾遗
      • 1. 回顾
      • 2. 源码分析
    • 二、 配置类扫描源码分析
      • 1. 源码分析
      • 2. BeanDefinition覆盖问题
      • 3. full配置类和lite配置类的区别

一、 拾遗

1. 回顾

前面我们分析了Spring框架器启动过程要做的事情,着重分析了ApplicationContext的refresh方法。但前面一节我们还遗留了refresh的两个重要方法还没有分析,分别是 invokeBeanFactoryPostProcessors(beanFactory)registerBeanPostProcessors(beanFactory),第一个方法的主要作用是扫描BeanDefinition和注册BeanDefinition,第二个方法的作用主要是注册BeanPostProcessor,都是为后序创建Bean做准备。

2. 源码分析

首先分析invokeBeanFactoryPostProcessors(beanFactory),在执行这句代码之前,spring主要是帮我们创建了一个BeanFactory,以及准备一些核心的Bean。在这之前先介绍一下BeanFactoryPostProcessor

BeanFactoryPostProcessor和BeanPostProcessor都是在Spring容器启动时进行一些额外处理的接口,但它们在容器生命周期中的阶段和用途上有一些区别。

  • BeanFactoryPostProcessor:

阶段: 在Spring容器实例化任何bean之前执行。
作用: 主要用于修改容器中的bean定义,例如修改bean的属性值、添加新的bean定义等。
接口方法: 只有一个方法postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 在这里可以修改bean的定义
        // 例如,修改属性值
        BeanDefinition bd = beanFactory.getBeanDefinition("myBean");
        bd.getPropertyValues().add("propertyName", "newValue");
    }
}

上面代码就给BeanDefinition添加了一个属性。

  • BeanPostProcessor:

阶段: 在容器实例化bean后,但在调用bean的初始化方法前后执行。
作用: 主要用于在bean初始化过程中执行一些定制的操作,例如代理、属性注入等。
接口方法: 有两个方法,postProcessBeforeInitialization和postProcessAfterInitialization。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化方法调用前执行
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化方法调用后执行
        return bean;
    }
}

总体而言,BeanFactoryPostProcessor用于在bean实例化前修改bean定义,而BeanPostProcessor用于在bean初始化过程中执行定制操作

BeanFactoryPostProcessor有一个子接口名字为BeanDefinitionRegistryPostProcessor,该接口扩展了BeanFactoryPostProcessor接口,提供了一个postProcessBeanFactory,允许我们向容器中注册BeanDefinition。

@Component
public class CService implements BeanDefinitionRegistryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws 
	//注册BeanDefinition
		beanFactory.registerDependentBean(....);BeansException {

	}
}

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,而ConfigurationClassPostProcessor这个类是就是扫描和注册beanDeifnition的核心。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {

}

进入invokeBeanFactoryPostProcessors(beanFactory)方法源码:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {

		// 重点
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		// 关于LoadTimeWeaver看这篇文章了解即可,https://www.cnblogs.com/wade-luffy/p/6073702.html
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

下面代码就拿到一些BeanFacotryPostProcessor(),但它不会扫描二是拿到容器中已经添加好的BeanFacotryPostProcessor(),比如我们使用·ApplicationContext.addBeanFactoryPostProcessor(自己定义的BeanFacotryPostProcessor)就会在这里被拿到。

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

进入invokeBeanFactoryPostProcessors方法。

//List<BeanFactoryPostProcessor>就包括两种类型,一种是BeanFactoryPostProcessor,另一种是BeanDefinitionRegistryPostProcessor,beanFactoryPostProcessors就是我们手动在refresh之前add的beanFactoryPostProcessors
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {   // BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();
         
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			// beanFactoryPostProcessors集合一般情况下都是空的,除非我们手动调用容器的addBeanFactoryPostProcessor方法添加了
			// beanFactoryPostProcessors中可能包含了:普通BeanFactoryPostProcessor对象和BeanDefinitionRegistryPostProcessor对象
			// 对于BeanDefinitionRegistryPostProcessor对象,会执行自己的postProcessBeanDefinitionRegistry()方法
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				//如果beanFactoryPostProcessors中添加的BeanFactoryPostProcessor有BeanDefinitionRegistryPostProcessor类型的,就首先执行其postProcessBeanDefinitionRegistry方法,然后添加到registryProcessors集合中。
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
				//如果是BeanFactoryPostProcessor类型,添加到regularPostProcessors集合中,进行分类处理
					regularPostProcessors.add(postProcessor);
				}
			}
             //定义一个BeanDefinitionRegistryPostProcessor类型的list集合
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// 执行扫描出来的BeanDefinitionRegistryPostProcessor,这里会拿出所有的`ConfigurationClassPostProcessor`,因为从spring启动的逻辑可以看出,ConfigurationClassPostProcessor这个类的beandefinition已经被spring提前放到容器中了
			String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
			//判断当前的BeanDefinitionRegistryPostProcessor是否实现了PriorityOrdered接口
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				//创建这个bean
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			// 升序排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			//执行postProcessBeanDefinitionRegistry方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				// processedBeans表示该beanFactoryPostProcessor的postProcessBeanDefinitionRegistry()方法已经执行过了,不再重复执行
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			// 执行哪些没有实现了PriorityOrdered或Ordered接口的普通BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
			// 在这个过程中可能会向BeanFactory中注册另外的BeanDefinitionRegistryPostProcessor,所以需要while,直到确定所有的BeanDefinitionRegistryPostProcessor都执行完了
			// 在这个过程中注册的BeanDefinitionRegistryPostProcessor,所实现的PriorityOrdered或Ordered接口可能会不按顺序执行
			// 比如 A注册了B和C,B又注册了D和E,那么B和C会按顺序执行,D和E也会按顺序执行,但是B、C、D、E整体不能保证是顺序执行
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			// 执行完BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法后,
			// 再执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

			// 执行手动添加的普通BeanFactoryPostProcessor的postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 执行扫描出来的普通BeanFactoryPostProcessor

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		// 先进行分类
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}

上面代码可以总结为下面的流程:

  • 执行通过ApplicationContext添加进来的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 执行BeanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法
  • 执行BeanFactory中实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 执行BeanFactory中其他的BeanDefinitionRegistryPostProcessor的 postProcessBeanDefinitionRegistry()方法
  • 执行上面所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
  • 执行通过ApplicationContext添加进来的BeanFactoryPostProcessor的 postProcessBeanFactory()方法
  • 执行BeanFactory中实现了PriorityOrdered接口的BeanFactoryPostProcessor的 postProcessBeanFactory()方法
  • 执行BeanFactory中实现了Ordered接口的BeanFactoryPostProcessor的 postProcessBeanFactory()方法
  • 执行BeanFactory中其他的BeanFactoryPostProcessor的postProcessBeanFactory()方法

下面再分析一下registerBeanPostProcessors(beanFactory);,前面说到这个方法的主要作用就是将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去。我们看看它源码是怎么做的:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        //从bean工厂中拿到所有BeanPostProcessor.class类型的beandefinition
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
		// beanProcessorTargetCount表示BeanFactory中所有的BeanPostProcessor数量,+1表示BeanPostProcessorChecker
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
        //初始化一系列集合
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		//对所有的BeanPostProcessor按照类型进行分类
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}
		// 升序排序
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		//添加到专门存储BeanPostProcessor的集合List<BeanPostProcessor> postProcessors中
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		// MergedBeanDefinitionPostProcessor排在最后
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		// ApplicationListenerDetector放在所有BeanPostProcessor之后,注意ApplicationListenerDetector的equals()方法实现
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

上面代码的主要逻辑就是先拿出所有的BeanPostProcessor的BeanDefinition,然后按照实现了PriorityOrdered接口,实现Ordered接口以及普通的BeanPostProcessor的顺序加入到List<BeanPostProcessor> postProcessors这个集合中,这个集合是工厂中专门用于存放BeanPostProcessor的集合。这就是控制BeanPostProcessor的执行顺序的机制。注意还有一个特殊的地方:

if (pp instanceof MergedBeanDefinitionPostProcessor) {
	internalPostProcessors.add(pp);
}

上面代码在registerBeanPostProcessors函数中多次出现,它的意思是如果某个BeanPostProcessor实现了MergedBeanDefinitionPostProcessor接口就会放入internalPostProcessors集合中,无论你是否实现了PriorityOrdered接口还是实现了Ordered接口。然后在函数最后会执行下面代码:

sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

这里对internalPostProcessors集合进行了排序,然后放到了postProcessors集合中,这就告诉我们,如果你的BeanPostProcessor实现了MergedBeanDefinitionPostProcessor接口,它一定是最后一批执行的BeanPostProcessor。到此registerBeanPostProcessors的逻辑就执行完了。

二、 配置类扫描源码分析

1. 源码分析

回到invokeBeanFactoryPostProcessors方法,的整个过程中它其实就会拿到ConfigurationClassPostProcessor这个类,然后执行它的postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法。前面我们说过ConfigurationClassPostProcessor是一个有关BeanDefinition的扫描和注册非常核心的方法,我们看看该类的这两个方法是在干什么:

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
....
@Override
	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);
	}

@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);

		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

....
}

首先看postProcessBeanDefinitionRegistry方法:

@Override
	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(registry);该方法就完成了spring配置类的解析。

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//拿到当前容器中所有已经注册好的BeanDefinition,此时我们自定义的BeanDefinition是拿不到的,因为现在还没开始BeanDifinition的扫描过程,
		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;
				}
			}
		}

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

上面代码首先执行String[] candidateNames = registry.getBeanDefinitionNames();,拿到当前容器中所有已经注册好了的BeanDefinition,包括前面在讲Spring启动时帮我们注册的一些核心BeanDefinition以及我们在容器refresh之前调用application.register注册的类。相信大家也注意到了applicationContext.register(AppConfig.class);这个类也被我们注册到了容器中,而AppCongif.class就是我们的配置类,所以上面这句代码是可以拿到我们的配置类的信息的。

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);

拿到所有的BeanDefinition后就会执行ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)来判断拿到的拿个类是配置类。然后执行configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));将所有的配置类加入到configCandidates这个候选配置类集合中。

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

		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());

		// 存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类
		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;
	}

上面代码中 Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());这一句就拿到了当前BeanDefinition的@Configuration注解中的属性,然后执行下面代码:

// 存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类
		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;
		}

如果存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类。这个就是第一个if语句的作用。

对于就是第二个else if的作用,它里面有一句isConfigurationCandidate(metadata),我们看看这个方法是干嘛

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
		//如果当前类是一个接口,说明就不是配置类
		if (metadata.isInterface()) {
			return false;
		}

		// Any of the typical annotations found?
		// 只要存在@Component、@ComponentScan、@Import、@ImportResource四个中的一个,就是lite配置类
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}

		// Finally, let's look for @Bean methods...
		// 只要存在@Bean注解了的方法,就是lite配置类
		return hasBeanMethods(metadata);
	}

candidateIndicators是一个集合,我们看看集合中有什么东西,

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

这就说明了如果当前类伤有@Component、@ComponentScan、@Import、@ImportResource注解中的任何一个注解,就会返回true,此时的注解为lite配置类。return hasBeanMethods(metadata);就是判断有没有@Bean注解,这说明只要该类内部有@Bean注解,它也是一个lite配置类。经过上面的代码就可以拿到我们的配置类了。继续回到processConfigBeanDefinitions方法。

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

如果获取的配置类集合为空,就直接返回了。

// 通过@Order可以排序,升序排序,order越小越靠前
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

如果有配置类,就会按照order对这些配置类进行排序,order越小的配置类越靠前。

ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

上面代码就是利用前面设置的一些信息去构建一个配置类的解析器。下面就开始真正的解析配置类了。

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

parser.parse(candidates); 这句代码将配置类传入到解析器中进行解析。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			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();
	}

上面代码首先遍历配置类集合configCandidates中的每一个配置类,然后调用真正的解析方法parse开始解析每一个配置类。

	protected final void parse(@Nullable String className, String beanName) throws IOException {
		Assert.notNull(className, "No bean class name for configuration class bean definition");
		//拿到配置类的一些元信息
		MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
		processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
	}

上面代码首先获取配置类的一些元信息,然后构建一个ConfigurationClass配置类作为参数调用processConfigurationClass开始真正解析配置类,我们进入该方法。

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,就会符合这个条件
				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);
			}
		}

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

上面方法的下面一段代码,其实递归解析父类,如果配置类继承了某个父类,它就会递归去解析父类。调用的核心方法是doProcessConfigurationClass

SourceClass sourceClass = asSourceClass(configClass, filter);
do {
	sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);

@Nullable
	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);
		}

		//处理@PropertySource注解
		//这段代码就是拿到我们的配置文件,然后解析配置文件放到SPring的环境变量中
		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;
	}

我们下面开始详细分析上面的代码,看看我们的配置类在Spring的底层到底是怎么解析的。

@Component
public class AppConfig {
	
}

上面我们的配置类只加了一个@Component注解,在上面方法中由下面代码解析这个注解。

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

上面代码首先判断当前配置类有没有@Component注解,如果有就会调用processMemberClasses方法。

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配置类,如果是就将配置类加入到candidates集合中等待解析
				if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
						!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
					candidates.add(memberClass);
				}
			}

			//重新对配置类候选集合candidates进行排序
			OrderComparator.sort(candidates);

            //这个for循环就是解决了外部类和内部类循环Import的一种情况
			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();
					}
				}
			}
		}
	}

根据上面代码我们可以知道,如果一个类加了@Component注解,Spring在解析配置类时,会拿出这种类的所有内部类,然后按照前面判断一个类是否时内部类的标准去判断内部类是否时配置类。所以这里就可以衍生出配置类的一种新的写法。

@Component
public class AppConfig {
	@Configuration
	class user{
	}
}

回到doProcessConfigurationClass方法。

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

上面代码就是用来处理@PropertySource注解,如果一个配置类上有这个注解,他就是拿出对应的配置文件,然后解析配置文件,将一些配置导入到Spring的环境变量Enviroment中。这里的解析配置文件的底层细节我们就不看了,继续看doProcessConfigurationClass的代码。

// 会进行扫描,得到的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());
					}
				}
			}
		}

上面代码就是重头戏,处理@ComponentScan注解,BeanDefinition的扫描过程就是这里面完成的。它会调用this.componentScanParser.parse这句代码,即扫描器去扫描所有的BeanDefinition,底层调用的方法就是scan方法,scan方法里面调用了doScan方法,这两个方法我们在前面Bean的生命周期中源码已经看过了,这里就不看了。然后扫描后会得到一个scannedBeanDefinitions,存放BeanDefinition的集合,类型是BeanDefinitionHolder,前面说吗这个累其实就是BeanDefinition和BeanName绑定到一起了。然后会判断扫描出来的BeanDefinition是不是配置类。如果是配置类我们会调用parse方法去解析,过程和上面一样。所以我们又可以衍生一种配置类写法。

@Component
public class BService {
	@Bean
	public AService aService(){
		return new AService();
	}
}

继续看doProcessConfigurationClass的代码。然后就是下面者句代码

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

上面这句代码就是用来解析@Import注解的。首先我们调用getImports方法,拿到注解中的信息。然后调用
processImports

	private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
		Set<SourceClass> imports = new LinkedHashSet<>();
		Set<SourceClass> visited = new LinkedHashSet<>();
		collectImports(sourceClass, imports, visited);
		return imports;
	}

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {

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

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
			//遍历import注解中导入的每一个类
				for (SourceClass candidate : importCandidates) {
					// 如果import的类实现了ImportSelector接口
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						// 如果import的是DeferredImportSelector,表示推迟导入
						//
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						} else {
							// 如果import的是普通的ImportSelector
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							// 继续处理selectImports()所返回的类
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					// 如果import的类实现了ImportBeanDefinitionRegistrar接口
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					// 如果import的类就是普通的类
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedBy
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}

上面就是解析@Import注解的源码,在解析之前它会拿到我们@Import注解中导入的所有类的信息,然后遍历,在处理这些导入类的时候,它分为了三中情况:

  • 类实现了ImportSelector接口
  • 类实现了ImportBeanDefinitionRegistrar接口
  • 类只是一个普通类

考虑下面这一种情况:

@Import(AService.class)
public class AppConfig {
	
}

public class AService  {
	@Bean
	public BService aService(){
		return new BService();
	}
}

上面@Import导入的就是一个普通的类,所以会进入下面这段代码进行处理:

else {

	this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedBy
	processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}

上面代码首先调用candidate.asConfigClass(configClass)将我们导入进来的类直接作为配置类,然后传递给processConfigurationClass,作为参数进行调用。

然后考虑下面这一种情况:

@Import(AService.class)
public class AppConfig {
	
}

public class AService  implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[0];
	}
}

由于导入的类实现了ImportSelector接口,所以它会执行下面的逻辑:

if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						// 如果import的是DeferredImportSelector,表示推迟导入
						//
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						} else {
							// 如果import的是普通的ImportSelector
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							// 继续处理selectImports()所返回的类
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}

上面代码首先会调用ImportSelector selector = ParserStrategyUtils.instantiateClass (candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry);将我们导入的类进行实例化然后转换成一个ImportSelector类型的实例对象。然后执行重写的selectImports方法。然后将该方法返回的类型,封装成一个importClassNames集合,然后递归调用processImports方法,再次进行处理。(实际上就是将selectImports方法返回的类作为导入进来的类,实现了这个接口的类可以作为批量导入的导入点)。

分析最后一种情况:

@Import(AService.class)
public class AppConfig {
	
}
public class AService  implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
		//该方法也可以用来注册BeanDefinition(Mybatis用到了这个)
	}
}

那么在processImports方法会执行下面这段逻辑:

else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}

上面代码同样将我们的导入类进行实例化然后转换为一个ImportBeanDefinitionRegistrar对象,但这里并没有调用重写方法,而是configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata())通过这句代码,将这个对象加入到当前配置类的importBeanDefinitionRegistrars属性集合上。

void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
		this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
	}

上面代码@Import的处理过程就分析完了。接着回到doProcessConfigurationClass方法。

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

处理完@Import注解就开始处理@ImportSource注解。使用这个注解我们可以直接导入一个xml文件,这里只是拿到了那个xml路径,然后加入到了当前配置类的importedResources属性中,并没有真正解析xml文件。然后继续看doProcessConfigurationClass方法。

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

上面就拿到了配置类中所有加了@Bean注解的方法,然后将这些方法封装到了当前配置类的beanMethod属性中。

// 解析配置类所实现的接口中的@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();
			}
		}

最后就是解析当前配置类实现的接口中是否有@Bean注解,如果有父类,就会返回这个父类(因为前面收到在解析配置类的过程中会递归解析父类),如果没有直接返回null即可,至此doProcessConfigurationClass方法就执行完毕了。

在这里插入图片描述

回到processConfigBeanDefinitions方法,前面我们调用parser.parse(candidates);将所有配置类已经解析完毕了

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

解析完毕后,所有配置类的解析结果会放在Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());这个集合中。然后我们分析一下这句代码this.reader.loadBeanDefinitions(configClasses);,这句代码的作用是加载BeanDefininition,但我们知道在doProcessConfigurationClass方法中处理@ComponentScan注解的时候,我们意见解析完了所有Bean,但这里为上面还有加载bean,大家是否还记得前面我们在解析Import的时候,将解析到的ImportBeanDefinitionRegistrars对象放入到了当前配置类的importBeanDefinitionRegistrars集合中,以及在解析@importReSrouce注解时,将一个xml配置文件记录到了当前配置类的importedResources中,以及在解析@Bean注解时,将所有的BeanMethod加入到了当前配置类的beanMethod,这三个属性是都有可能产生额外的bean的,所以我们需要对这些额外的bean进行加载,而这个过程就是在this.reader.loadBeanDefinitions这个方法中实现的。

	public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

上面方法就会遍历已经解析过的配置类,然后调用loadBeanDefinitionsForConfigurationClass方法。

private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
			// 将被导入的类生成BeanDefinition并注册到Spring容器中
			// @Component的内部类,@Import所导入的类都是被导入的类
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}

		// @Bean生成BeanDefinition并注册
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		// 处理@ImportResource("spring.xml")
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

		// 处理ImportBeanDefinitionRegistrar,调用registerBeanDefinitions()方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

首先执行下面这段代码:

for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

这里就是获得beanmethod的属性,然后执行loadBeanDefinitionsForBeanMethod方法,调用beanmethod去注册beandefinition到容器中。

同样loadBeanDefinitionsFromImportedResources就是解析xml,将所有的beandefinition注册到容器中,loadBeanDefinitionsFromRegistrars就会拿到ImportBeanDefinitionRegistrars方法,然后调用它的registerBeanDefinitions方法。但我们注意一个问题,我们新导入的beandefinition会不会也是配置类,所以回到processConfigBeanDefinitions方法中的下面这段代码:

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

if (registry.getBeanDefinitionCount() > candidateNames.length)会判断是不是新增加了BeanDefinition,如果是ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactor这句代码就判断新增加的BeanDefinition是不是新的配置类,如果是就加入到candidates这个未解析的配置类集合中(这个集合前面已经清空了,避免重复解析),然后再次执行上面的所有逻辑,解析配置类,这也是为什么这里用do…while循环的原因。这里分析一个奇怪的现象,我先给出一个代码:


public class AppConfig {
	@Bean
	public AppConfig1 appConfig1() {
		return new AppConfig1();
	}
}

public class AppConfig1 {
	@Bean
	public AService aService(){
		return new AService();
	}
}

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		applicationContext.register(AppConfig.class);
		applicationContext.refresh();
		Object aService = applicationContext.getBean("aService");
		applicationContext.close();
	}

在这里插入图片描述
我们发现拿不到AService这个bean,如果我们把AppConfig1改为配置文件xml定义就可以拿到,这是为什么呢。其实这是Spring底层偷了个懒,ConfigurationClassUtils.checkConfigurationClassCandidate这个函数,检查新增的bean是否是配置类时,在获取@Bean而新增bean得名字时会为null,所以checkConfigurationClassCandidate方法中的这句代码,就会直接返回false,判断当前bean不为配置类。

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

上面时补充的一个当前spring版本的一个缺陷。至此ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法就分析完了,配置类的解析,以及BeanDefinition的扫描和注册源码就解析完了。

2. BeanDefinition覆盖问题

  • @Component名字相同
@Component("Aservice")
public class AService  {

}

@Component("Aservice")
public class BService {

}

在这里插入图片描述

直接报错,这里我们在看Bean生命周期源码的时候,在分析doScan方法时讨论过BeanDefiniiton的兼容性问题。

  • @Bean注解名字相同
@ComponentScan("com.zhouyu")
@EnableScheduling
@PropertySource("classpath:spring.properties")
@EnableTransactionManagement
public class AppConfig {
	@Bean
	public AService aService(){
		return new AService();
	}
	@Bean
	public AService aService(BService bService){
		return new AService();
	}

}

不会报错,这里前面在分析methodbean得时候,在解析methodbean生成beanDefinition,它只会使用一个beanMethod生成BeanDefinition,其它的都不会生效。

  • @Bean和@Component名字相同

这里会覆盖,由于@Component先解析,然后解析@Bean,分析源码可以看到@Bean的会覆盖@Component(如果当前Spring是允许覆盖的)。

3. full配置类和lite配置类的区别

前面ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法已经分析完了,现在我们进入ConfigurationClassPostProcessorpostProcessBeanFactory方法。

@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);

		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

上面enhanceConfigurationClasses就增强了我们的配置类。

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();

		// 遍历,找出配置类
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
			AnnotationMetadata annotationMetadata = null;
			MethodMetadata methodMetadata = null;
			if (beanDef instanceof AnnotatedBeanDefinition) {
				AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
				annotationMetadata = annotatedBeanDefinition.getMetadata();
				methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
			}
			if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
				// Configuration class (full or lite) or a configuration-derived @Bean method
				// -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
				// or component class without @Bean methods.
				AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;

				// 没有加载类就去加载
				if (!abd.hasBeanClass()) {
					boolean liteConfigurationCandidateWithoutBeanMethods =
							(ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
								annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
					if (!liteConfigurationCandidateWithoutBeanMethods) {
						try {
							abd.resolveBeanClass(this.beanClassLoader);
						}
						catch (Throwable ex) {
							throw new IllegalStateException(
									"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
						}
					}
				}
			}
			if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
				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() || NativeDetector.inNativeImage()) {
			// nothing to enhance -> return immediately
			enhanceConfigClasses.end();
			return;
		}

		// 生成代理类,并设置到BeanDefinition中  Full Config
		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);
			// Set enhanced subclass of the user-specified bean class
			Class<?> configClass = beanDef.getBeanClass();  // Appconfig
			// 生成代理类
			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);
			}
		}
		enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
	}

上面代码的核心逻辑就是将full 配置类生成一个代理对象,这时候full配置类在容器中对应的bean对象都会是代理对象,在我们使用beanmethod实际去创建bean对象的时候,就会由代理对象去调用这些beanmethod去创建bean。在doCreatebean创建bean的时候,@Bean的beanMethod创建bean时会由一个factoryBean去创建这个factoryBean就是full配置类代理的那个bean。

在这里插入图片描述
下面给出一个小的案例更好的理解:

@Configuration(proxyBeanMethods = false) //此时是lite
public class AppConfig {
	@Bean
	public AService aService(){
		System.out.println(bService());
		System.out.println(bService());
		return new AService();
	}
	@Bean
	public BService bService(){
		return new BService();
	}

}

此时aService打印的两个bService不同
在这里插入图片描述
这是为什么啊,这是因为在lite模式下,当前的配置类没有代理对象,所以aService直接调用了bService方法创建了两个不同的对象。但是在full模式下,在代理对象执行某个方法的时候,会有一个拦截器拦截判断当前执行的方法是否是一个创建bean的方法,显然在System.out.println(bService());执行这句代码的时候,不是在创建bean对象,所以代理逻辑会让它直接getbean()而是调用bService()去创建一个新的对象。而当前确实是工厂方法在调用bService创建对象,它就会真正的创建对象。这里还是比较难理解的,感兴趣可以结合源码分析一下。

@Configuration(proxyBeanMethods = true) //此时是lite
public class AppConfig {
	@Bean
	public AService aService(){
		System.out.println(bService());
		System.out.println(bService());
		return new AService();
	}
	@Bean
	public BService bService(){
		return new BService();
	}

}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/311559.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

只有金蝶用户,才懂金蝶BI方案的含金量

资深金蝶系统用户都看得明明白白&#xff0c;金蝶系统侧重于企业资源的计划和管理&#xff0c;而当前企业数字化运营决策不仅需要高效合理的流程管理&#xff0c;更需要一套完善的数据分析方案&#xff08;金蝶BI方案&#xff09;&#xff0c;无缝对接金蝶系统&#xff0c;智能…

【Kafka-3.x-教程】-【五】Kafka-监控-Eagle

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

软件测试|Python如何将列表从大到小排序

简介 在编程中&#xff0c;对列表进行排序是一个常见的操作&#xff0c;有时候我们需要将列表按照从大到小的顺序进行排列。Python 提供了多种方法来实现这一目标。在本文中&#xff0c;我们将深入探讨几种将列表从大到小排序的方法&#xff0c;帮助您根据不同情况选择最合适的…

OpenHarmony—开发环境搭建

背景 因为没有实体的开发硬件&#xff0c;且不想破坏原有的Linux环境&#xff0c;所以这里基于 Docker QEMU 搭建开发环境 宿主机Linux系统命令行方式DockerQEMU 6.2 Docker环境准备 安装Docker 在Ubuntu中&#xff0c;可以使用下面的命令来安装Docker&#xff1a; sudo …

HarmonyOS自定义组件生命周期函数介绍

aboutToAppear 在创建自定义组件的新实例后&#xff0c;在执行其build()函数之前执行。允许在aboutToAppear函数中改变状态变量&#xff0c;更改将在后续执行build()函数中生效。 aboutToDisappear 在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变…

SpringBoot怎么写一个自定义的starter,Gradle依赖引入starter的Jar包

1.新建一个Spring的项目myasset-spring-boot-starter 项目结构如下: 注意:不需要Application启动类 和 application.yml/application.properties文件 2. resources下添加spring.factories文件 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigu…

基于知识图谱的健康知识问答系统

基于知识图谱的健康知识问答系统 引言数据集与技术选型数据集技术选型 系统功能与实现数据导入与图数据库构建问答任务设计与实现1. 实体提取2. 用户意图识别 前端聊天界面与问答系统 结语 引言 随着互联网的发展&#xff0c;人们对健康知识的需求逐渐增加。为了更方便地获取健…

pytorch12:GPU加速模型训练

目录 1、CPU与GPU2、数据迁移至GPU2.1 to函数使用方法 3、torch.cuda常用方法4、多GPU并行运算4.1 torch.nn.DataParallel4.2 torch.distributed加速并行训练 5、gpu总结 1、CPU与GPU CPU&#xff08;Central Processing Unit, 中央处理器&#xff09;&#xff1a;主要包括控制…

【AIGC】一组精美动物AI智能画法秘诀

如何使用AI绘画&#xff0c;从以下角度&#xff0c;依据表格内容梳理&#xff0c;表格如下&#xff1a; 外貌特征物种姿势特征描述场景风格技术描述小巧可爱幼小浣熊倚在桌子上具有人形特征中世纪酒馆电影风格照明8k分辨率细节精致毛茸茸手持咖啡杯Jean-Baptiste Monge的风格蓝…

【AIGC-文本/图片生成视频系列-8】Align your Latents: 基于潜在扩散模型的高分辨率视频合成

目录 一. 项目概述与贡献 二. 方法详解 三. 应用总览 四. 个性化视频生成 五. 实时卷积合成 六. 更多结果 七. 论文 八. 个人思考 AI生成高分辨率视频一直是一个挑战。 今天讲解一篇潜在扩散模型&#xff08;LDM&#xff09;用于高分辨率、时间一致且多样化的视频生成…

模拟数字转换器

本节主要介绍以下内容&#xff1a; ADC简介 ADC功能框图详解 参考资料:《零死角玩转STM32》“ADC—电压采集”章节 一、ADC简介 ADC &#xff1a;Analog to Digital&#xff0c;模拟数字转换器 三个独立的ADC 1 / 2 / 3分辨率为12位每个ADC具有18个通道&#xff0c;其中…

自旋锁和互斥锁的区别

自旋锁和互斥锁的区别_自旋锁和互斥锁有什么区别?-CSDN博客

网工内推 | 高级网工,H3C认证优先,朝九晚六,周末双休

01 万德 招聘岗位&#xff1a;高级网络工程师 职责描述&#xff1a; 1、项目交付&#xff1a;项目管理和交付&#xff0c;包括项目前期的规划、实施以及后期的运维支持、项目验收等。 2、技术支持&#xff1a;为客户及合作伙伴提供网上问题远程和现场支持&#xff1b;对公司内…

【MySQL】锁机制

文章目录 一、表级锁和行级锁二、排他锁和共享锁三、InnoDB行级锁行级锁间隙锁意向共享锁和意向排他锁 四、InnoDB表级锁五、死锁六、锁的优化建议 一、表级锁和行级锁 表级锁&#xff1a; 对整张表加锁。开销小&#xff0c;加锁快&#xff0c;不会出现死锁&#xff1b;锁粒度…

msvcp140_codecvt_ids.dll缺失的解决方法,dll文件全面解析

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140CODECVTIDS.dll丢失”。那么&#xff0c;msvcp140CODECVTIDS.dll是什么文件&#xff1f;它的作用是什么&#xff1f;为什么会丢失&#xff1f;本文将详细介绍msvcp140CODECVTIDS.d…

你知道程序员如何利用citywork实现财富自由吗?

周末到了&#xff0c;我要去citywalk寻找心灵的呼吸&#xff01;”有谁没有设想过疲惫的工作日之后好好地去走一走&#xff0c;亲近大自然呢&#xff1f;谁又不想在闲暇之余唤起对生活的趣味呢&#xff1f;可是对于我们悲催的打工人而言&#xff0c;没有citywalk&#xff0c;只…

在WindowsServer2012中部署war项目

目录 前言 一.jdk安装 二.Tomact安装 三.MySQL安装 ​编辑​编辑​编辑​编辑​编辑​编辑​编辑 四.开放端口号 MySQL开放端口号 Tomact开放端口号 ​编辑 五.项目部署 1.将war放置在tomact中 2.配置项目sql脚本 3.最终效果 前言 安装Java开发工具包&#xff08…

ROS2——Parameters

节点可以使用参数来配置各项操作&#xff0c;这些参数可以说布尔值、整数、字符串等类型。节点在启动时会读取参数。我们将参数单独列出来&#xff0c;而不是写在源文件中&#xff0c;这样做可以方便我们调试&#xff0c;因为在不同的机器人、环境中&#xff0c;我们需要的参数…

Java并发编程——伪共享和缓存行问题

在Java并发编程中&#xff0c;伪共享&#xff08;False Sharing&#xff09;和缓存行&#xff08;Cache Line&#xff09;是与多线程访问共享数据相关的两个重要概念。 伪共享指的是多个线程同时访问同一个缓存行中的不同变量或数据&#xff0c;其中至少一个线程对其中一个变…

EM planner 论文阅读

论文题目&#xff1a;Baidu Apollo EM Motion Planner 0 前言 EM和Lattice算法对比 EM plannerLattice Planner参数较多&#xff08;DP/QP&#xff0c;Path/Speed&#xff09;参数少且统一化流程复杂流程简单单周期解空间受限简单场景解空间较大能适应复杂场景适合简单场景 …