1.写在前面
上一篇博客中讲到的Spring
的扫描机制,但是讲的是Spring
提供给外部的api,而且创建的在AnnotationConfigApplicationContext
的构造函数中创建的scanner
属性,创建的ClassPathBeanDefinitionScanner
对象,Spring
自己根本没有使用,这个对象是暴露给外部的人使用的。今天我们就真正来讲下Spring
是如何扫描的?这里要注意的是Spring
扫描也是用这个类的,但是Spring
没有用这个scanner
属性,而是自己重新创建了一个ClassPathBeanDefinitionScanner
对象的,所以机制也是一样的,主要的是这两个过滤函数。同时会涉及到一些BeanFactoryPostProcessor
的知识,这儿笔者建议读者:最好将笔者的整个Spring
的源码系列全都看了,不然可能会看不懂。Spring
的体系过于庞大,一篇两篇博客,讲不清楚,笔者写的每一篇博客都是有关联的。
2.BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor
凡是了解过Spring
的人,都是知道实现这个接口的类,都会对BeanDefinition
进行修改,然后再放到BeanFactory
的BeanDefinitionMap
的集合中去。但是Spring
在初始化的时候,只会添加5个默认的BeanDefinition
,分别是ConfigurationClassPostProcessor
(BeanFactoryPostProcessor
)、AutowiredAnnotationBeanPostProcessor
(BeanPostProcessor
)、CommonAnnotationBeanPostProcessor
(BeanPostProcessor
)、EventListenerMethodProcessor
(BeanFactoryPostProcessor
)、DefaultEventListenerFactory
,注意:如果这儿添加了JPA的支持的话,会再添加一个PersistenceAnnotationBeanPostProcessor
,然后会调用AnnotationConfigApplicationContext
中register
方法,将我们的配置类也会注册进来。那么就会有6个。那么可能读者就有疑问了。那么我们自己写Bean还没有转换成BeanDefinition添加到BeanDefinitionMap中去呀,那么又是怎么添加进去的呢?又是谁添加的呢?我们现在已经知道了默认的BeanDefinitionMap
中已经有了6个BeanDefinition
对象。那么肯定是其中那个对象呢?笔者作为一个新手,第一次阅读Spring
的源码,那么我们该怎么知道是那个对象呢?唯一的办法就是打断点,然后看对应的调用栈,那么该怎么打断点呢?让我们想到了上篇博客中写道的。扫描Class
将其转成BeanDefinition
并添加到BeanDefinitionMap
中去,是调用的是doscan
方法,于是笔者在对应的方法上打了一个断点。具体的如下:
我们最终发现调用的是ConfigurationClassPostProcessor
类中的方法。
2.1执行顺序
既然知道了是调用这个类中方法,那么Spring
又是怎么调用它的?又是调用它中的那个方法呢?这就是本节要回答的问题。
先回答第一个问题,Spring怎么调用到它的?在那个方法中调用的。我们可以看上面的调用栈。我们发现最终的调用链如下:
AnnotationConfigApplicationContext#init()
--->AbstractApplicationContext#refresh()
--->AbstractApplicationContext#invokeBeanFactoryPostProcessors()
--->PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
后面的调用链,我没有继续写了,是因为这个方法比较重要,笔者这里要讲一下这个方法。具体的代码如下:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
//DefaultListableBeanFactory这个类实现了BeanDefinitionRegistry,这个判断是会进
if (beanFactory instanceof BeanDefinitionRegistry) {
//用一个变量存起来
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//创建一个BeanFactoryPostProcessor的集合
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//创建一个BeanDefinitionRegistryPostProcessor的集合
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//这个时候beanFactoryPostProcessors的集合为空
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
//创建一个BeanDefinitionRegistryPostProcessor的集合,表示当前的要执行的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
//从BeanFactory的BeanDefinitionMap中取出实现BeanDefinitionRegistryPostProcessor的类型的键名,
//这个时候只能取出一个,就是ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//判断是否实现了PriorityOrdered接口,这个时候取出来的是ConfigurationClassPostProcessor
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//添加到currentRegistryProcessors集合中去
//getBean的含义:如果容器中这个对象已经创建好了,直接取,如果容器中这个对象没有创建好,那我们就new
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//存入对应的名字
processedBeans.add(ppName);
}
}
//对BeanDefinition进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//添加到registryProcessors
registryProcessors.addAll(currentRegistryProcessors);
//执行BeanDefinitionRegistryPostProcessor的接口的实现类ConfigurationPostProcessor中的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空当前要执行的集合
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
//再次查找实现BeanDefinitionRegistryPostProcessor接口的类名
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//查询出来的如果上次没有执行过同事也是实现Ordered接口的实现类,会进入这个判断
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
//同时添加到当前要执行BeanDefinitionRegistryPostProcessor的集合
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
//同时添加到对应的集合,可以简单说就是执行过的
processedBeans.add(ppName);
}
}
//进行排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//添加到总的
registryProcessors.addAll(currentRegistryProcessors);
//执行接口中实现类的指定的方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清除当前的集合
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
//再次查找
boolean reiterate = true;
//这个死循环就能保证所有实现BeanDefinitionRegistryPostProcessor的接口类都会执行
while (reiterate) {
reiterate = false;
//查找实现BeanDefinitionRegistryPostProcessor接口的实现类
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);
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//执行所有所有实现BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,这儿可能会有人说这儿不是执行了两次,
//然而并不是,因为里面进行了对应的判断,判断对应的hash的值
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//执行所有所有实现BeanFactoryPostProcessor的postProcessBeanFactory方法,这个默认是为空的,
//只有通过调用addBeanFactoryPostProcessor()的BeanFactoryPostProcessor才会在这执行。
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
//获取对应实现BeanFactoryPostProcessor接口的类
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 实现PriorityOrdered和BeanFactoryPostProcessor接口的类,最先执行
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 实现Ordered和BeanFactoryPostProcessor接口的类,次之执行
List<String> orderedPostProcessorNames = new ArrayList<>();
// 实现BeanFactoryPostProcessor接口的类,最后执行
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.
// 对实现PriorityOrdered和BeanFactoryPostProcessor接口的类进行排序
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));
}
// 对实现Ordered和BeanFactoryPostProcessor接口的类进行排序
sortPostProcessors(orderedPostProcessors, beanFactory);
// 执行接口对应的方法
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
// 只实现了BeanFactoryPostProcessor的接口的类存入下面的集合。
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();
}
虽然上面的代码写了注释,但是自己还是总结一下吧!不然对读者来说看的是云里雾里。
总结,执行顺序如下:
- 最先执行的是通过调用
addBeanFactoryPostProcessor()
方法添加的的BeanDefinitionRegistryPostProcessor
接口的实现类中的postProcessBeanDefinitionRegistry()
方法。如果有多个,是按照添加的顺序来执行的。 - 然后执行同时实现了
PriorityOrdered
和BeanDefinitionRegistryPostProcessor
接口中的实现类中的postProcessBeanDefinitionRegistry()
方法。如果有多个,按照对应的排序规则来执行的。 - 再执行同时实现
Ordered
和BeanDefinitionRegistryPostProcessor
接口中的实现类中的postProcessBeanDefinitionRegistry()
方法。如果有多个,按照对应的排序规则来执行的。 - 再执行实现了
BeanDefinitionRegistryPostProcessor
接口中的实现类中的postProcessBeanDefinitionRegistry()
方法。如果有多个,就按照添加的顺序来执行。 - 再执行
BeanDefinitionRegistryPostProcessor
接口中的实现类中的postProcessBeanFactory()
方法。如果有多个,就按照添加的顺序来执行。 - 再执行通过调用
addBeanFactoryPostProcessor()
方法添加的的BeanFactoryPostProcessor
接口的实现类中的postProcessBeanFactory()
方法。如果有多个,是按照添加的顺序来执行的。 - 再执行同时实现了
PriorityOrdered
和BeanFactoryPostProcessor
接口的实现类中的postProcessBeanFactory()
方法。如果有多个,按照对应的排序规则来执行的。 - 再执行同时实现了
Ordered
和BeanFactoryPostProcessor
接口的实现类中的postProcessBeanFactory()
方法。如果有多个,按照对应的排序规则来执行的。 - 最后执行实现了
BeanFactoryPostProcessor
接口的实现类的postProcessBeanFactory()
方法。如果有多个,按照添加的顺序来执行。 - 注意:Spring并没有完全保证每一个类只执行一次。如果我们通过
addBeanFactoryPostProcessor()
方法添加的的BeanFactoryPostProcessor
接口的实现类,然后给这个类添加@Component
注解,这个时候就会执行两次 - 具体的执行的流程如下图:
这个时候读者可能有疑问,BeanDefinitionRegistryPostProcessor
又是什么接口?我们只知道BeanFactoryPostProcessor
接口。这儿笔者告诉你这个BeanDefinitionRegistryPostProcessor
就是BeanFactoryPostProcessor
的子接口。这个时候我们已经讲完了对应invokeBeanFactoryPostProcessors()
方法,但是我们还没有讲到对应ConfigurationClassPostProcessor
类。我们来看下对应继承的类图,具体如下:
我们可以看到这个类实现BeanDefinitionRegistryPostProcessor
、BeanFactoryPostProcessor
、Ordered
、PriorityOrdered
接口。那么由上面的执行顺序和AnnotationConfigApplicationContext
的初始化的过程,我们可以得知最先执行的是这个类中postProcessBeanDefinitionRegistry
方法。
2.2ConfigurationClassPostProcessor
由上面的调用链可知,我们发现调用的是invokeBeanDefinitionRegistryPostProcessors的方法,具体的代码如下:
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
//循环调用所有的BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanDefinitionRegistry的方法
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
上面的代码就是循环调用所有的BeanDefinitionRegistryPostProcessor
接口的实现类的postProcessBeanDefinitionRegistry
的方法,我们直接查看ConfigurationClassPostProcessor
中的postProcessBeanDefinitionRegistry()
,具体的代码如下:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//获取对应的hash的值
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
//添加到指定的集合中去,表示已经注册过了
this.registriesPostProcessed.add(registryId);
//关键的代码
processConfigBeanDefinitions(registry);
}
然后会调用对应的 processConfigBeanDefinitions()
的方法,具体的代码如下:
//这个方法过于复杂,由于博客的篇幅有限,不会全都讲,只会讲重点的部分。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//用来存BeanDefinition的包装类BeanDefinitionHolder
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//这儿会取出所有的目前容器中BeanDefinition,现在是6个
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
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) {
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集合中去,配置类可能有多个
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析对应的配置类
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
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();
}
}
3.什么样的类可以解析成配置类?
什么样的类可以作为我们的配置类呢?一定要加@Configuration
的类吗?下面就由笔者为你一一解答这个问题。由于上面的代码太长,我们直接取出我们核心要将的部分。具体的代码如下:
//这儿会取出所有的目前容器中BeanDefinition,现在是6个
String[] candidateNames = registry.getBeanDefinitionNames();
//遍历获取对应的配置类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判断这个org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass是不是为空
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;
}
上面的candidateNames
取出来的值现在应该是6个,也就是目前BeanFactory
中的所有的BeanDefinition
,这儿其中有5个是Spring
提供的,并不是我们自己的,所以Spring
要找出我们的配置类。
走来Spring
会先判断这个BeanDefinition
中的attribute
的属性的键为org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
的是不是不等于null
,这个属性在解析讲BeanDefinition
的时候已经讲过了。这儿对应的五个为空的。我们这儿可以搞一个破坏,哈哈!就是在Spring
容器初始化之前,我们将AppConfig
的BeanDefinition
的信息给改了,让这个值不为null
,那么就不会有对应的配置类,就会报错!我们可以试下效果,具体的代码如下:
package com.ys.annotationConfigApplicationContextTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration()
@ComponentScan("com.ys.annotationConfigApplicationContextTest")
public class AppConfig {
}
package com.ys.annotationConfigApplicationContextTest;
import org.springframework.stereotype.Component;
@Component
public class A {
}
package com.ys.annotationConfigApplicationContextTest;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
AnnotatedGenericBeanDefinition appConfig = (AnnotatedGenericBeanDefinition) context.getBeanFactory().getBeanDefinition("appConfig");
//修改对应的属性的值。
appConfig.setAttribute("org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass", true);
context.refresh();
context.getBean(A.class);
}
}
运行结果如下:
如果我们将我们修改的属性的那个代码注释掉,这个就不会报错,具体的运行结果如下:
通过这个例子,上面的那个判断应该理解更透彻了吧。我们继续看原来的代码,具体的代码如下:
//这儿会取出所有的目前容器中BeanDefinition,现在是6个
String[] candidateNames = registry.getBeanDefinitionNames();
//遍历获取对应的配置类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判断这个org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass是不是为空
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;
}
如果我们不搞破坏的话,第一个判断是不会进的,我们继续看第二个判断ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)
,具体的代码如下:
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
//获取对应的className
String className = beanDef.getBeanClassName();
//有可能是通过工厂方法注解进来的BeanDefinition,直接返回false
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
AnnotationMetadata metadata;
//判断是不是AnnotatedBeanDefinition的BeanDefinition,还记得我第一篇博客中的内容,就知道这个接口有三个实现类。
//分别是AnnotatedGenericBeanDefinition、ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
// 获取对应的bean注解的元数据存起来
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {//所有的BeanDefinition都会满足
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
//取出对应的BeanClass
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
//判断是不是下面的四种类型的一种。
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
//取出这个Configuration这个注解的数据
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {//不为空,同时判断方法需不需要代理
//给对应的属性org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass设置为full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {//如果没有该注解,则调用isConfigurationCandidate(metadata)方法
//给对应的属性org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass设置为lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {//都不成立直接返回false
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
// 判断是否有order注解,有直接取出来,然后将其设置到attribute中去
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
上面的判断,如果是实现AnnotatedBeanDefinition
的BeanDefinition
或者是AbstractBeanDefinition
但不是BeanFactoryPostProcessor
、BeanPostProcessor
、AopInfrastructureBean
、 EventListenerFactory
,再或者是自己实现的BeanDefinition
添加到BeanDefinitionMap
中的BeanDefinition
就不会返回false
然后进行第二次筛选,如果是添加了Configuration
注解的类是不会返回false的,还有种就是isConfigurationCandidate(metadata)
方法的返回值不为false的,也是不会返回false的,那么这个方法中是做了什么?具体的代码如下:
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
//如果是接口直接返回false
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
//Component ComponentScan Import ImportResource 四个注解中一个会返回true
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// Finally, let's look for @Bean methods...
try {
//最后一种有方法添加了这个@Bean注解
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
}
return false;
}
}
上面的方法,我们可以得知,如果是接口会直接返回false
,如果是Component
ComponentScan
Import
ImportResource
四个注解中一个会返回true
,如果在方法上添加了@Bean
注解也是会返回true
。所以最终的解答这个问题,什么样的类可以解析成配置类?
当这个BeanDefinition
是AnnotatedBeanDefinition
或者是AbstractBeanDefinition
但不是BeanFactoryPostProcessor
、BeanPostProcessor
、AopInfrastructureBean
、 EventListenerFactory
,再或者是自己实现的BeanDefinition
,同时这个BeanDefinition
如果加了Configuration
的注解,并且这个注解的proxyBeanMethods
的值为true
,就会将org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
设置为full
或者没有加Configuration
的注解,但是这个BeanDefinition
不是接口,或者是Component
ComponentScan
Import
ImportResource
四个注解中一个再或者是有方法添加了Bean
注解这样的BeanDefinition就会将org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
设置为lite
所以满足上面的两种情况的任何一种都可以被解析成配置类。至此这节介绍完了。接下来我们看怎么调用doscan
的方法的。
4.Spring如何调用到doscan的方法
通过断点调试,我们发现调用的 parser.parse(candidates);方法,将刚才找到的配置进行进行解析,具体的代码如下:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
这儿三个判断真好对应前面的三种情况的BeanDefinition
的解析。这儿我们只需要看第一个if
中的方法parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
同时将注解的元数据和对应的BeanName
传进去了。具体的代码如下:
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//扫描的方法在这个方法中
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
由于篇幅的原因,我们只介绍重要的方法 doProcessConfigurationClass(configClass, sourceClass, filter);
,具体的代码如下:
@Nullable
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
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
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
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();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
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
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
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;
}
- 看这上面的代码,真的是头皮发麻,所以这儿笔者抽出处理
ComponentScan
的部分的代码,具体的代码如下:
//取出ComponentScan注解中的数据
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
//判断是不是为空
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
//这儿应该就只有一个,因为只加了一个ComponentScan注解
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//解析ComponentScan注解
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();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
- 上面的方法
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
方法就是解析ComponentScan
注解,具体的代码如下:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//重新创建了一个ClassPathBeanDefinitionScanner,并且是否使用默认的配置,是由注解中指定的。这个如果没有设置的话,就使用的是默认
//就会给includeFilters添加一个Component注解
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"),
this.environment, this.resourceLoader);
//获取对应的名字的生成规则
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
//如果已经给定自己的生成规则就使用的自己的
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
//获取作用域代理模型并设置好
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
// **/*.class,这个也可以指定扫描的后缀
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
//包含在内的注解,自己定义
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
//不包含在内的注解,自己定义
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//获取是否是懒加载的
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
//扫描的路径
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
//将当前AppConfig排除在外,因为这个东西已经注解了BeanDefinition。所以要排除在外。
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//终于调用到我们的doscan的方法了
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
至此这儿定义了我们自动的ClassPathBeanDefinitionScanner
,大部分的东西都是从注解中获取的。这儿会给ExcludeFilter
属性中添加一个排除当前配置类的,因为配置类已经注册过了。然后就会调用到我们的doScan()
方法了。至此终于讲完了。
5.写在最后
这篇博客主要讲BeanFactoryPostProcessor
和BeanDefinitionRegisterPostProcessor
的执行顺序,同时讲了一下Spring
中很重要的一个类ConfigurationClassPostProcessor
类,最后和上一篇博客关联起来,讲了一下Spring
是怎么调用的doscan
的方法。