:::info 前置知识:设计模式、数据结构、jvm、多线程、反射

注意事项:

  1. 不专注细节
  2. 画图(时序图、流程图、总结图)
  3. 看注释(类、接口、方法)
  4. 见名知义
  5. 大胆猜测小心验证
  6. 坚持

:::

搭建Spring5.3.x源码阅读环境

[实战]从零到一搭建Spring 5.3.x版本源码本地搭建_哔哩哔哩_bilibili

Spring Farmework 中的设计模式应用

适配器模式:AbstractXmlApplicationContext中的loadBeanDefinitions方法

实例化Bean过程

画板

在不同阶段执行不同的事件,怎么办?

观察者模式:监听器,监听事件,多播器

Spring中的重要接口

画板

refresh()方法包含spring启动的核心流程,在AbstractApplication类中。

prepareRefresh()刷新前的准备工作
  1. 初始化系统启动时间,一些标志位
  2. 创建Enviroment对象
  3. 准备监听器和事件集合对象(用于方便扩展)
obtainFreeshBeanFactory()获取Bean工厂

子类实现

  1. 创建DefualtListableBeanFactory
  2. (加载xml文件)
prepareBeanFactory()准备Bean工厂
  1. 设置类加载器、SPEL解析器
  2. 忽略Aware实现类的注入
postProcessBeanFactory()

子类实现

invokeBeanFactoryPostProcessors() 执行所有注册的BFPP Bean
  1. 执行所有注册的BeanFactoryPostProcessor对象 先执行排序的(Ordered)再执行未排序的
registerBeanPostProcessors() 实例化并注册所有BPP
  1. 实例化并注册所有BeanPostProcessor Bean 后续执行BPP的准备工作
initMessageSource()国际化操作

小项目用不到

initApplicationEventMulticaster() 初始化事件广播器

准备工作

onRefresh()

空方法 子类实现

registerListeners() 注册监听器

准备工作

finishBeanFactoryInitialization() 实例化所有剩下的非懒加载单例对象
  1. 初始化类型转换操作相关参数
  2. 判断beanfactory有无内置值处理器
  3. 处理AOP织入相关操作
  4. 设置临时ClassLoader
  5. 冻结不修改的Bean
  6. 实例化所有非懒加载单例对象
    1. 遍历beanDefinitionName
    2. (合并子类和父类的Bean定义信息
    3. (doGetBean 获取或者创建Bean
      1. 获取BeanNames
      2. 从三级缓存中获取Bean
      3. 缓存中没有对象则开始创建Bean
      4. 尝试解决循环依赖问题
      5. 获取父类容器
      6. 标志位已创建对象
      7. 获取并检测beanDefinition
      8. 如果有依赖Bean递归创建依赖的Bean
      9. doCreateBean 实例化和初始化对象
        1. 使用反射实例化对象
        2. 处理循环依赖
        3. 填充属性
        4. 执行Aware接口方法
        5. 执行BeanPostProscessor:before方法
        6. 执行init方法
        7. 执行BeanPostProscessor:after方法
        8. 注册销毁对象方法
    4. 加入一级缓存
    5. 如果该Bean是FactoryBean,则通过其getObject再创建一个Bean

画板

:::info 子类对象创建时父类对象也要创建,所以创建子类时会调用父类的构造函数。所以我们遇到new有父类的对象时,需要查看父类的构造函数,看父类构造函数做了什么,调用了什么方法。

:::

  1. ClassPathXmlApplicationContext一系列父类初始化 初始化一些属性
    • AbstractApplicationContext类初始化
      • 创建一些对象,包括id上下文唯一标识、active``closed标志位、monitor
      • 创建了一个资源模式处理器 PathMatchingResourcePatternResolver
      • 此类初始化
        • 创建Ant表达式匹配处理器
      • 设置父容器
    • AbstractXmlApplicationContext初始化
      • 设置标志位validating用于验证配置文件
  2. ClassPathXmlApplicationContext初始化
    • 设置配置文件路径setConfigLocations(),方便后续直接调用
      • 进行一些解析处理,例如检查存在,替换占位符等。创建StandardEnvironment使用其中的属性,替换占位符
  3. 调用**refresh**方法
    • 加锁startupShutdownMonnitor
    • prepareRefresh()刷新前的准备工作
      • 初始化一些属性
      • initPropertySources() 可以做一些扩展操作,如设置所需属性,后续验证是否存在
      • 获取Environment,并验证所需属性是否存在
      • 设置application监听器集合、设置事件集合 spring中不需要 在spring boot中需要
    • obtainFreshBeanFactory
      • 刷新Bean工厂设置属性、xml文件
        • 创建 DefaultListableBeanFactory
          • allowCircularReferences = true 自动解决循环依赖
          • ignoreDependencyInterface Aware类
          • 设置父类Bean工厂
        • 生成容器唯一id
        • customizeBeanactory()
        • loadBeaDefinitions() 使用代理模式
          • doRegisterBeanDefinitions()
          • parseBeanDefinitionElement()

设计模式

AbstractRefreshableConfigApplicationContext中有一个configLocations之后会用

**StandardEnvironment**初始化过程

调用无显示定义的无参构造方法,调用父类AbstractEnvironment构造方法 因为没有显示定义,所以要在父类构造方法处打断点,才能查看具体流程

设置忽略属性值spring.getenv.ignore

激活的属性文件spring.profiles.active

默认属性文件spring.profiles.default

等等一些初始化工作

回到StandardEnvironment执行customizePropertySources方法

设置systemEnvironment(操作系统环境变量)systemProperties(jvm系统属性)

Environment=Property(配置)+Profile(环境)

Spring Boot 核心接口之 Envirnoment

**PathMatchingResourcePatternResolver**实现接口**ResourceLoader**用于加载资源

BeanFactory相关接口、类、方法

  • ListableBeanFactory 可以枚举所有Bean实例
  • ConfigurableBeanFactory 提供配置Bean工厂的一些方法
  • HierarchicalBeanFactory 使Bean工厂具有继承关系
  • DefaultListableBeanFactory 使用较多
  • doGetBean() 每次操作时先从父工厂中获取 主要存在于Spring MVC中

Java的初始化顺序规则:

  1. 父类成员变量默认初始化
  2. 父类显示初始化和父类初始化块
  3. 父类构造器 如果使用super()显示调用必须放在子类构造器第一行
  4. 子类成员变量默认初始化
  5. 子类显式初始化和子类初始化块
  6. 子类构造器

三级缓存为了解决循环依赖

@Configuration

标注到类上,启动Spring就会自动注册Bean到Ioc容器

自动执行@Bean方法,将Bean定义信息注册到IOC容器

可以代替applicationContext.xml文件

value bean的id

本质上是@Component

这个类中可以使用Bean Autowired Inject Resource 等注解注入所需Bean对象

  1. AnnotationConfigApplicationContext使用包路径
  2. this 创建scanner reader
  3. doScan 扫描指定包
  4. scanCandidateComponents扫描候选类
  5. processCommonDefinitionAnnotations处理注解
  6. registerBeanDefinition 将beanName和BeanDefinition放入beanDefinitionMap和beanDefinitionNames
  7. registerAnnotationConfigProcessors注册所有相关注解后置处理器
  8. refresh刷新容器
  9. invokeBeanFactoryPostProcessors运行所有BFPP
  10. ConfigurationClassPostProcessor enhanceConfigurationClasses 增强配置类,使其可以对Bean方法进行拦截

ConfigurationClassPostProcessor解析Configuration注解

BeanFactoryPostProcessors

BeanDefinitionRegistryPostProcessors 注册新的Bean

@Bean

将当前方法的返回值注入到IOC容器中

获取Bean

AbstractApplicationContext 通用上下文实现 invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate 处理和和注册后置处理器 invokeBeanFactoryPostProcessors

AbstractBeanFactory 创建和缓存Bean doGetBean

DefaultSingletonBeanRegistry 管理单例 bean getSingleton

AbstractAutowireCapableBeanFactory 用于默认Bean创建 createBean doCreateBean createBeanInstance instantiateBean

SimpleInstantiationStrategy 用于 BeanFactory 的简单对象实例化策略 instantiate

BeanUtil instantiateClass

@Import

注解使用场景:配置较多,使用import进行分类管理。引入第三方类。

ImportSelector 用于组合配置类 ImportBeanDefinitionRegistrar用于加载Bean定义

BeanFactoryPostProcessor 在Bean定义加载后进行修改

BeanDefinitionRegistryPostProcessor 动态注册新的Bean定义火大规模修改Bean定义 在其他BeanFactoryPostProcessor之前执行

ConfigurationClassPostProcessor 解析处理类及其注解 proessConfigBeanDefinitions postProcessBeanDefinitionRegistry processConfigBeanDefinitions

ConfigurationClassParser 配置类解析器 doProcessConfigurationClass parse processImports处理Impot注解

ImportSelector selectImports 获取想要注入的类的类名 需要自己实现

将配置类解析为ConfigurationClass

ConfigurationClassBeanDefinitionReader 读取ConfigurationClass类,注册其中的Bean定义 loadBeanDefinitions

AnnotationMetadata 带有注解的类的元数据

DefaultListableBeanFactory 实现BeanDefinitionRegistry注册储存Bean定义的功能。实现BeanFactory获取Bean的功能

DefaultSingletonBeanRegistry 储存单例对象

配置类解析相关类

@PropertySource

加载配置文件,将配置文件放到环境变量中

PropertySourceRegistry processPropertySource

DefaultPropertySourceFactory 加载配置文件 createPropertySource

PropertiesPropertySource 封装Properties作为属性源

PropertySourceProcessor 属性源处理 addPropertySource

@ComponentScans

扫描对应包下标注@Component注解、@Configuration注解等等注解的类。

@ComponentScan 注解用于指定 Spring 扫描组件的范围。

ComponentScanAnnotationParser 解析@ComponentScan注解 parse

ClassPathBeanDefinitionScanner 扫描类路径下的Bean定义,注册到容器 registerBeanDefinition

ClassPathScanningCandidateComponentProvider 在类路径下扫描

@DependsOn

指定当前Bean对象所依赖的其他Bean对象

可以改变实例化顺序
AnnotatedBeanDefinitionReader (读取和解析配置类)和 ClassPathBeanDefinitionScanner (扫描包下的类)都是 Spring Framework 中用于注册 Bean 定义的类

注册Bean

AnnotatedBeanDefinitionReader doRegisterBean 从注解中读取元数据设置到BeanDefinition中,在注册到容器中

BeanDefinition 接口:管理Bean属性和元数据

调用后置处理器

@Conditional

将满足条件的Bean注册到容器中

使用场景:

  1. 需要在不同环境运行,读取不同的配置信息

ConditionEvaluator 评估是否符合条件 shouldSkip

ConfigurationClassParser processConfigurationClass 中使用shouldSkip跳过配置类

@Lazy

优化启动性能

AbstractApplicationContext preInstantiateSingletons 在此时Lazy没有被实例化

@Component

将自己创建的类注入到IOC容器中

AnnotationConfigUtils.processCommonDefinitionAnnotations(abd) 处理以下注解:@Lazy、@Primary、@DependsOn、@Role、@Description 这些注解将会被设置到元数据中

ConfigurationClassParser doProcessConfigurationClass 处理以下注解:@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean、default方法、配置类的父类

ConfgurationClassPostProcessor processConfigBeanDefinitions

ConfigurationPhase 也就是PARSE_CONFIGURATION阶段会忽略配置类,REGISTER_BEAN阶段忽略普通类

ClassPathBeanDefinitinScanner doScan 扫描指定包

ClassPathScanningCandidateComponentProvider addCandidateComponentsFromIndex 使用componentsIndex加载组件类 scanCandidateComponents直接扫描指定包加载组件类

componentsIndex的加载过程涉及读取由构建工具(如Maven或Gradle)生成的类路径索引文件(通常是META-INF/spring.components)

@Value

由后置处理器BeanPostProcessor处理

AbstractAutowireCapableBeanFactory populateBean 填充属性

initializeBean 初始化Bean 执行Aware接口、执行BeanPostProcessor:Before、执行初始化方法、BeanPostProcessor:After

AbstractAutowireCapableBeanFactory 有自动装配功能的Bean工厂 populateBean填充属性

AutowiredAnnotationBeanPostProcessor 处理通过@Autowire和@Value注入属性 postProcessProperties

InjectionMetadata inject 遍历成员,注入属性

DefaultListableBeanFactory doResolveDependency 解决依赖@Autowired、@Value

QualifierAnnotationAutowireCandidateResolver 解析给定Bean是否是合适的自动装配候选者

  • isAutowireCandidate
  • getSuggestedValue
  • determineAUtowireCandidate
  • getLazyResolutionProxyIfNecessary

StandardBeanExpressionResolver evalutate

SpelExpression getValue

SpelNodeImpl 其实现表示各种操作符 getValue

StandardEvaluationContext spel运算上下文

@Autowire

自动按照类型注入

行AutowiredTest类

运行AutowiredTest类的main()方法,输出的结果信息如下所示。
  1. autowiredDao===>>>io.binghe.spring.annotation.chapter12.dao.AutowiredDao@1ba9117e
  2. autowiredService=>>>AutowiredService{autowiredDao=io.binghe.spring.annotation.chapter12.dao.AutowiredDao@1ba9117e}
  3. @冰河: 代码已经复制到剪贴板
1
2 可以看到,打印了从IOC容器中获取到的AutowiredDao类的Bean对象和AutowiredService类的Bean对象,并且向AutowiredService类中注入的AutowiredDao类的Bean对象和直接从IOC容器中获取的AutowiredDao类的Bean对象是同一个对象。

#四、源码时序图

结合时序图理解源码会事半功倍,你觉得呢? 注意:本章也可以从解析并获取 @Autowired修饰的属性、为 @Autowired修饰属性赋值和使用@Autowired获取属性值三个方面分析源码时序图。获取 @Autowired修饰的属性、为 @Autowired修饰属性赋值的源码时序图基本与@Value注解相同,使用@Autowired注解获取属性值的源码时序图略有差异。使用@Autowired注解获取属性值的源码时序图如图12-1~12-2所示。

Spring Formwork 源码阅读解析 - 图5

#查看完整文章

加入冰河技术(opens new window)知识星球,解锁完整技术文章与完整代码