Spring主要加载链路分析

包扫描

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath />
</parent>
  • application.run => prepareEnvironment 准备环境

    • 发布事件 BootstrapApplicationListener => bootstrap 会触发一个application.run
  • bootstrap的run执行完后,继续执行原application.run,也就是prepareEnvironment 处理完后,refreshContext刷新上下文

  • AbstractApplicationContext #invokeBeanFactoryPostProcessors

  • PostProcessorRegistrationDelegate #invokeBeanDefinitionRegistryPostProcessors

    • for 后置处理器 #postProcessBeanDefinitionRegistry
  • ConfigurationClassPostProcessor #processConfigBeanDefinitions

    • BeanDefinitionRegistry注册表 获取初始BeanDefinition
    • for 校验获取可用配置类,一般都是项目的启动类
    • 分析配置类 319行 parser.parse(…) => processConfigurationClass()
  • ConfigurationClassParser #doProcessConfigurationClass 289行开始根据扫描路径开始扫描包

    • 296行 ComponentScanAnnotationParser #parse 包扫描解析,根据ComponentScan注解配置对扫描器进行配置,然后执行扫描 scanner.doScan(…)
    • ClassPathBeanDefinitionScanner #doscan 通过类加载器以及配置路径,从编译后文件中获取,获取@Component相关类,不满足则过滤,最后返回全部可自动装配类
  • for 处理包扫描结果集

    • 自动装配相关类都会通过校验,主要关注以下方法

      1
      2
      3
      ConfigurationClassUtils 
      #checkConfigurationClassCandidate()
      #isConfigurationCandidate()
    • 缓存到元数据读取工厂 metadataReaderFactory

    • processConfigurationClass() 递归处理

配置类处理逻辑

  • ConfigurationClassParser #processConfigurationClass

    • 获取配置类缓存 configurationClasses
      • 已存在缓存,配置类与 @Imported 有关,则执行完相关逻辑后直接return
      • 已存在缓存,配置类与 @Imported 无关,讲配置类从缓存中去除,继续执行重新加载(具体处理原因源码中有注释)
    • 递归处理配置类及其父类 #doProcessConfigurationClass 有父类则通过方法返回值赋值,递归处理
    • 配置类放入缓存 configurationClasses
  • ConfigurationClassParser #doProcessConfigurationClass

    • 配置类是否有 @Component ,有则先递归处理内部类 #processMemberClasses

      • TODO
    • 处理 @PropertySource

    • 处理 @ComponentScan 包扫描

      • ComponentScanAnnotationParser #parse 包扫描解析,根据ComponentScan注解配置对扫描器进行配置,然后执行扫描 scanner.doScan(…)

        ClassPathBeanDefinitionScanner #doscan => #findCandidateComponents 通过类加载器以及配置路径,从编译后文件中获取。

        #isCandidateComponent(MetadataReader metadataReader) 获取可自动装配类,包括 @Component,具体看方法实现,其中includeFilters包含了@Component

      • for 处理包扫描结果集

        1. 转换成BeanDefinition

        2. 校验BeanDefinition,主要关注以下方法,一般自动装配类都会通过校验

          1
          2
          3
          ConfigurationClassUtils 
          #checkConfigurationClassCandidate()
          #isConfigurationCandidate()
        3. 通过校验后解析相应BeanDefinition #parse(String className, String beanName)

        4. 缓存到元数据读取工厂 metadataReaderFactory

        5. processConfigurationClass() 递归处理

    • 处理 @Import

      • 先通过 #getImports() 获取导入配置类,当前类上注解 => 注解上的注解,递归获取相关注解有过滤逻辑:

        1
        2
        3
        // ConfigurationClassParser
        Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
        (className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."));
      • @import导入的配置类也会加入缓存 metadataReaderFactory

    • 处理 @ImportResource

    • 处理 @Bean

      • 获取全部 @Bean 相关方法
      • 当相关方法为复数时,且元数据是由反射生成(original instanceof StandardAnnotationMetadata)。因为反射无需,需要排序
      • 根据@Bean结果集,给配置类添加 BeanMethod
    • 处理接口默认方法

    • 处理父类

      • knownSuperclasses 缓存已处理过的父类
      • 有父类就返回父类,外层循环递归处理父类 return sourceClass.getSuperClass();
    • 没有父类返回null,结束递归 return null;