书接上文
文章目录
- 一、 拾遗
- 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 {@Overridepublic 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 {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 在初始化方法调用前执行return bean;}@Overridepublic 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 {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws //注册BeanDefinitionbeanFactory.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.htmlif (!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)) {//创建这个beancurrentRegistryProcessors.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类型的beandefinitionString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// beanProcessorTargetCount表示BeanFactory中所有的BeanPostProcessor数量,+1表示BeanPostProcessorCheckerint 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 {
....
@Overridepublic 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);}@Overridepublic 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
方法:
@Overridepublic 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 foundif (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 contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {// 可以预先往单例池中添加一个CONFIGURATION_BEAN_NAME_GENERATOR的BeanNameGenerator类型的bean// 可以用来作为扫描得到的Bean和import导入进来的Bean的beanNameBeanNameGenerator 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 classConfigurationClassParser 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());// 递归解析配置类,有可能通过解析一个配置类,得到了其他的配置类,比如扫描和Importtdo {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass// 解析配置类的结果是什么?parser.parse(candidates); // AppConfig.class--->BeanDefinitionparser.validate();// configClasses相当于就是解析之后的结果Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResourcethis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClasscandidates.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 classesif (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,则直接取AnnotationMetadataif (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得到AnnotationMetadataelse 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--->BeanDefinitionparser.validate();// configClasses相当于就是解析之后的结果Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResourcethis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClasscandidates.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);@Nullableprotected 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 neededfor (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 annotationsAnnotationAttributes 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 anyif (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 recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn 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,就出现了循环importif (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 {@Configurationclass 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 neededfor (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 {@Beanpublic 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 importsClass<?> 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的是普通的ImportSelectorString[] 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 definitionsClass<?> 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 classthis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedByprocessConfigurationClass(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 {@Beanpublic BService aService(){return new BService();}
}
上面@Import
导入的就是一个普通的类,所以会进入下面这段代码进行处理:
else {this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 注意,在asConfigClass方法中,不仅会将candidate生成一个ConfigurationClass,还会记录一下candidate是被哪个类导入的importedByprocessConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);}
上面代码首先调用candidate.asConfigClass(configClass)
将我们导入进来的类直接作为配置类,然后传递给processConfigurationClass
,作为参数进行调用。
然后考虑下面这一种情况:
@Import(AService.class)
public class AppConfig {}public class AService implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[0];}
}
由于导入的类实现了ImportSelector
接口,所以它会执行下面的逻辑:
if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector -> delegate to it to determine importsClass<?> 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的是普通的ImportSelectorString[] 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 {@Overridepublic 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 definitionsClass<?> 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 anyif (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 recursereturn 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--->BeanDefinitionparser.validate();// configClasses相当于就是解析之后的结果Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResourcethis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClasscandidates.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--->BeanDefinitionparser.validate();// configClasses相当于就是解析之后的结果Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition// 比如一个配置类中有多个@Bean,一个配置配置了@ImportResourcethis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();// candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClasscandidates.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 {@Beanpublic AppConfig1 appConfig1() {return new AppConfig1();}
}public class AppConfig1 {@Beanpublic 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版本的一个缺陷。至此ConfigurationClassPostProcessor
的postProcessBeanDefinitionRegistry
方法就分析完了,配置类的解析,以及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 {@Beanpublic AService aService(){return new AService();}@Beanpublic AService aService(BService bService){return new AService();}}
不会报错,这里前面在分析methodbean得时候,在解析methodbean生成beanDefinition,它只会使用一个beanMethod生成BeanDefinition,其它的都不会生效。
- @Bean和@Component名字相同
这里会覆盖,由于@Component先解析,然后解析@Bean,分析源码可以看到@Bean的会覆盖@Component(如果当前Spring是允许覆盖的)。
3. full配置类和lite配置类的区别
前面ConfigurationClassPostProcessor
的postProcessBeanDefinitionRegistry
方法已经分析完了,现在我们进入ConfigurationClassPostProcessor
的postProcessBeanFactory
方法。
@Overridepublic 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 immediatelyenhanceConfigClasses.end();return;}// 生成代理类,并设置到BeanDefinition中 Full ConfigConfigurationClassEnhancer 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 classbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);// Set enhanced subclass of the user-specified bean classClass<?> 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 {@Beanpublic AService aService(){System.out.println(bService());System.out.println(bService());return new AService();}@Beanpublic 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 {@Beanpublic AService aService(){System.out.println(bService());System.out.println(bService());return new AService();}@Beanpublic BService bService(){return new BService();}}