ConfigurationClassPostProcessor如何完成扫描配置类的包
ConfigurationClassPostProcessor如何完成扫描配置类的包
0、概念
当前章节只来分析ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry中的扫描包阶段,其他的之后再来进行分析。
一、ConfigurationClassPostProcessor先执行的方法
在spring默认的BD中,只有ConfigurationClassPostProcessor符合这里的条件。既实现了BeanDefinitionRegistryPostProcessor接口,也实现了PriorityOrdered接口。
需要先执行BeanDefinitionRegistryPostProcessor接口中的postProcessBeanDefinitionRegistry方法。
二、源码执行阶段
那么下面具体来分析一下扫描过程
根据方法名称可以看到,处理配置类对应的BD的。那么spring是如何知道哪些是配置类的BD呢?
2.1、获取得到当前容器中的BD,判断哪些是配置类
这里的一步主要是为了获取得到配置类的BD,这里使用了循环。
使用循环的目的是程序员可能提供了多个配置类
这里重点spring是为了做什么?就是为了来解析配置类。因为在配置类上,通常会有对应的扫描包路径以及自定义的一些bean
如何检查BD是否是一个配置类的
这里存在着一行关键性代码,如下所示:
AnnotationMetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())
) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
如果beanDef是AnnotatedBeanDefinition类型的以及配置类的className和元注解中的className是相同的,那么将会利用AnnotatedBeanDefinition类型的来拿到对应的元注解信息(也就是说不能是内部类)
而当前的BD中,只有自定义的配置类AppConfig是AnnotatedBeanDefinition类型的BD,所以这里判断成功。
对应的代码存在于三行代码中的第二行代码:
applicationContext.register(AppConfig.class);
然后利用元信息来进行解析类上信息
如果配置类上有@Configuration注解,这里又分为了两种情况:
①proxyBeanMethods=true,beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
②proxyBeanMethods=false,beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
在这里只是来做一个记录,标记这个BD是一个配置类
为什么要用FULL或者是LITTLE来做记录呢?这里将会在CGLIB中起着举重若轻的地位,这里终于用到了BD中的额外信息来进行补充说明了。
但是直到现在只是对配置类做了判断,但是没有执行到解析阶段。
所以执行阶段是先找到对应的配置类,然后再来解析配置类。
所以在上面最开始的时候,有一个利用判断是否解析的阶段
将没有解析过的配置类保存起来,然后在下面进行解析
首先创建配置类的解析类,然后对配置类来进行解析。
那么我们现在先直接分析根据配置类找到了对应的扫描的包的情况,其他的情况之后再来做一个分析。
直接找到关键性代码来进行分析
parser.parse(candidates);
看一下具体的执行过程
2.2、扫描阶段
代码分析到了这里,一切都显得非常清晰了。
2.2.1、为什么new了ClassPathBeanDefinitionScanner
从第一行代码中分析
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
从这里可以看到,开发人员可以根据自己的需求来设定是否使用默认的过滤器,可以使用,也可以不使用。这里是留给开发人员来进行配置的。
主要是为了自定义配置性
如下所示:
@ComponentScan(basePackages = "com.guang.spring",useDefaultFilters = false)
@Configuration
public class AppConfig {
}
可以不用spring提供的内置的默认过滤器,而来使用开发人员自己提供的。