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提供的内置的默认过滤器,而来使用开发人员自己提供的。

三、ConfigurationClassPostProcessor完成包扫描总结

posted @ 2023-01-03 15:03  写的代码很烂  阅读(16)  评论(0编辑  收藏  举报