• Spring IOC源码研究笔记(2)——ApplicationContext系列


    1. Spring IOC源码研究笔记(2)——ApplicationContext系列

    1.1. 继承关系

    非web环境下,一般来说常用的就两类ApplicationContext:

    • 配置形式为XML的:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext

    • 配置形式为注解的:AnnotationConfigApplicationContext

    前者的继承链为:AbstractApplicationContext -> AbstractRefreshableApplicationContext -> AbstractRefreshableConfigApplicationContext -> AbstractXmlApplicationContext。

    后者的继承链为:AbstractApplicationContext -> GenericApplicationContext。

    注意,AbstractRefreshableConfigApplicationContext实现了InitializingBean(回调为如果自己没有启动,那么就refresh)、BeanNameAware(表明如果它自己作为bean的时候,将会知道自己的bean name)。

    GenericApplicationContext还实现了BeanDefinitionRegistry接口:委托给自己持有的DefaultListableBeanFactory实现。

    1.2. ApplicationContext

    接口,继承了:ListableBeanFactory、HierachicalBeanFactory、ResourcePatternResovler、MessageSource、ApplicationEventPublisher、EnvironemntCapable。

    • 返回:ID、name、display name、启动时间、父app ctx、自己内部的autowire capable bean factory

    1.3. ConfigurableApplicationContext

    继承自ApplicationContext、LifeCycle、Closable。

    • 添加了一些配置的功能:

      • 设置id

      • 设置parent app ctx

      • 设置、获取environment

      • 设置class loader

      • 添加protocol resolver(来自DefaultResourceLoader)

      • 添加bean factory post processor

      • 添加application listener

    • 然后是涉及生命周期的一些方法:

      • refresh

      • close

      • 添加shutdown hook

      • 判断是否active

    1.4. AbstractApplicationContext

    AbstractApplicationContext实现了ConfigurableApplicationContext接口。

    AbstractApplicaitonContext继承于DefaultResourceLoader从而实现了ApplicationContext要求的ResourceLoader的方法。

    AbstractApplicationContext通过实例字段持有一个ResourcePatternResolver实例(构造函数中使用自身作为resource loader来new一个PathMatchingResourcePatternResolver),从而通过委托的方式实现了ApplicationContext要求的ResourcePatternResolver的方法。

    AbstractApplicationContext通过实例字段持有一个MessageSource实例(initMessageSource时初始化),从而通过委托的方式实现了ApplicationContext要求的MessageSource中的方法。

    AbstractApplicationContext的子类通过持有DefaultListableBeanFactory(AbstractRefreshableApplicationContext、GenericApplicationContext),从而实现了ApplicationContext、ConfigurableAppliationContext暴露BeanFactory的功能。

    AbstractApplicationContext通过实例字段持有LifeCycleProcessor从而通过委托的方式实现了AplicationContext要求的Lifecycle中的方法。

    AbstractApplicationContext通过实例字段持有ApplicationEventMulticaster从而实现了ApplicationContext要求的ApplicationEventMulticaster中的方法。

    由上可见,对于ApplicationContext、ConfigurableApplicationContext中定义的方法其实就refresh值得看,其他的方法要不就是简单的set方法,要么就是其他的接口而来,被委托给其他类或者继承自其他类,从而实现。

    1.4.1. refresh方法

    refresh方法是ApplicationContext最重要的方法了,它定义了

    1.4.1.1. prepareRefresh

    一个ConfigurableApplicationContext可能被refresh多次:

    做了三件事:

    • 设置状态字段:active(true)、closed(false)、startUpDate(currentTimeMillis)

    • 属性相关:initPropertySource(在Web环境下的ApplicationContext中重写)、验证标记为required的属性是否都可以解析。

    • 消息发布相关:把applicationListeners设置为第一次refresh之前的样子。创建一个空的“早期事件容器”(registerListener步骤之前发布的事件会暂存在这个容器中,在registerListener的时候,取出所有ApplicationListener添加到ApplicationEventMulticaster中,并发布这些暂存的事件,并将该容器置null。)

    1.4.1.2. obtainFreshableBeanFactory

    refreshBeanFactory是个抽象方法,在子类中实现。

    • 对于GenericApplicationContext来说,它的构造函数中就将DefaultListableBeanFactory给new出来了,并持有它,refreshBeanFactory只是给它设置id、以及设置标记位。

    • 对于AbstractRefreshableApplicationContext来说:它销毁旧bean factory,然后创建一个新的bean factory,设置id后,就从xml文件中加载bean definition。

    1.4.1.3. prepareBeanFactory

    对beanfactory进行了一些配置:

    • 配件设置:

      • 设置beanfactory的bean classloader(application自己的,ResourceLoader中的方法——如果显式set的话就用set的,没有的话使用当前线程的context classloader,还没有的话就用ClassUtils的classloader,再没有的话就用system classloader)

      • bean expression resovler(StandardBeanExpressionResolver)

      • property editor registrar(ResourceEditorRegistrar)。

    • 依赖设置:

      • 忽略掉bean一些依赖:EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware、ApplicationContextAware、MessageSourceAware、EmbeddedValueResovlerAware(就算bean依赖于这些类型的bean,也不为它注入这些依赖)。

      • 添加一些现成就能用的依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicaitonContext(如果bean依赖这些类型的bean,那么直接将本AbstractApplicationContext将作为候选的注入值),当有bean依赖这种类型的bean时,直接返回本application context

    • 添加bean post processor:ApplicationContextAwareProcessor、ApplicationListenerDetector。

    • 如果存在loadTimeWeaver这个名称的bean(跟aop相关,类加载时织入),那么给beanfactory设置tempclass loader(bean factory的bean classloader创建一个ContextTypeMatchClassLoader),同时添加一个LoadTimeWeaverAwareProcessor(bpp,他给LoaderTimeWeaver类型的bean设置LoadTimeWeaver,这个LoadTimeWeaver来自bean factory)。

    • 将environment中的一些数据封装为单例bean实例注册到beanfactory中。

    1.4.1.4. postProcessBeanFactory

    在AbstractApplicationContext中为空方法,在一些web环境下的子类中被重写。

    1.4.1.5. invokeBeanFactoryPostProcessors

    如果bean factory没有tempClassLoader但注册了LoadTimeWeaver bean,那么就添加一个LoadTimeWeaverAwareProcessor这个bpp,然后设置一个ContextTypeMatchClassLoader作为tmpClassLoader。

    接下来由于逻辑太长比较复杂,专门抽到PostProcessorRegistrationDelegate类中:

    传入的beanFactoryPostProcessor是此前其他组件直接调用AppCtx的addBeanFactoryPostProcessor添加的bean factory postprocessor(在SpringBoot的情况下有:CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor、PropertySourceOrderingPostProcessor)。

    另外一部分bean factory post processor是作为bean definition注册在bean factory中。(AnnotationConfigApplicationContext在构造时会构造AnnotatedBeanDefinitionReader,进而会往添加一些用于注解处理的bfpp。)

    • 如果bean factory实现了BeanDefinitionRegistry接口(一般来说肯定走这个逻辑,因为只有一个DefaultListableBeanFactory):

      1. 遍历传入的bean factory post processor,将其中的bean definition registry post processor和一般的bean factory post processor分开,并用其中的bean definition registry post processor的postProcessBeanDefinitionRegistry方法处理app ctx的bean factory

      2. 然后再从app ctx的bean factory中取出所有PriorityOrdered类型的bean definition registry post processor类型的bean,排序后,用其postProcessBeanDefinitionRegistry方法依次处理app ctx的bean factory,并将其保存下来以供去重。

      3. 然后再从app ctx的bean factory中取出所有只是Ordered类型的没用过的bean definition registry post processor类型的bean,排序后,用其postProcessBeanDefinitionRegistry方法依次处理app ctx的bean factory,并将其保存下来以供去重。

      4. 然后再取出剩下的普通优先级没用过的bean definition registry post processor,用其postProcessBeanDefinitionRegistry方法r处理app ctx的bean factory。注意由于postProcessBeanDefinitionRegistry时可能会向bean factory中注册新的bean definition registry post processor类型的bean,因此用广度优先的方式进行不断的迭代,直到没有为止。

      5. 将上面的这些bean definition registry post processor按照同样的顺序,使用其postProcessBeanFactory方法来处理bean factory

      6. 将入参中的bean factory post processor的postProcessBeanFactory方法处理bean factory。

    • 如果bean factory没有实现BeanDefinitionRegistry接口(基本不可能走这里):

      • 遍历入参中的bean factory post processor来postProcessBeanFactory。

    最后取出BeanFactory中的BeanFactoryPostProcessor类型并且没用过的Bean,按照PriorityOrdered -> Ordered -> Regular优先级的顺序对BeanFactory进行后处理。

    注意:

    1. 对于PriorityOrdered、Ordered优先级的后处理器,它们在处理前都需要进行排序,而regular优先级的不用排序。

    2. 对BDRPP和BFPP的处理不相同,BDRPP在后处理时可能引入新的BDRPP,因此采用广度优先搜索的方式,需要多次遍历Bean Factory中的BDRPP。而BFPP,直接遍历一次Bean Factory中的BFPP,不进行广度优先搜索。

    3. 上面的排序,一般使用AnnotationAwareOrderComparator来排序:实现了PriorityOrdered -> 实现了Ordered -> Spring的@Order -> javax的@Priority

    整体的顺序为:

    1. 非bean方式的BDRPP先postProcessBeanDefinitionRegistry

    2. bean方式的并且是PriorityOrdered的BDRPP,排序后,postProcessBeanDefinitionRegistry

    3. bean方式的并且是Ordered的BDRPP,排序后,postProcessBeanDefinitionRegistry

    4. bean方式的非Ordered的BDRPP,postProcessBeanDefinitionRegistry

    5. 上面的BDRPP,相同顺序来postProcessBeanFactory

    6. 非bean方式的BDRPP,postProcessBeanFactory

    7. bean方式的并且是PriorityOrdered的BFPP,排序后,postProcessBeanFactory

    8. bean方式的并且是Ordered的BFPP,排序后,postProcessBeanFactory

    9. bean方式的非Ordered的BFPP,postProcessBeanFactory

    1.4.1.6. registerBeanPostProcessors

    由于方法太长,委托给PostProcessorRegistrationDelegate这个静态工具类处理。

    添加一个BeanPostProcessorChecker。

    再将隐式的以bean形式存在于容器中的BeanPostProcessor取出来:

    • 先取出PriorityOrdered类型的,排序后,显示地添加到bean factory中(addBeanPostProcessor)

    • 再取出Ordered类型的,排序后,显示地添加到bean factory中

    • 再取出普通优先级的,显示地添加到bean factory中

    • 如果上面的BeanPostProcessor还是MergedBeanDefinitionPostProcessor(被称为internal bean post processor),排序后,再进行一次addBeanPostProcessor(注意这个操作会首先remove然后再add,相当于是说,如果再后面又add了一个之前add过的,就只是把这个往后挪而已。)

    • 最后添加一个ApplicationListenerDetector(将其放在最后)。

    1.4.1.7. initMessageSource

    如果本地beanfactory中没有messageSource这个bean,那么new一个DelegatingMessageSource设置好它的parent后(DelegatingMessageSource是HierachicalMessageSource,这个parent要么是当前app ctx的父app ctx内部的MessageSource,要么就是父app ctx),交给application context,同时将其作为单例注册到bean factory中。

    1.4.1.8. initApplicationEventMulticaster

    ApplicationContext实现了ApplicationEventPublisher接口,这个功能的实现是借助ApplicationEventMulticaster的(作为字段)。

    这个字段的实例化在initApplicationEventMulticaster方法中。

    如果本地beanFactory中有ApplicaitonEventMulticaster类型的bean,那么就采用这个bean。(注意一定是本地beanFactory,因为父级beanFactory在发布事件的时候子beanFactory添加的ApplicationListener不会接收到,而子beanFactory发布的事件,父beanFactory的application listener会接收到,见publishEvent方法)。

    如果本地beanFactory中没有注册这个bean的话,原地实例化一个SimpleApplicationEventMulticaster作为字段,并将其作为singleton注册到beanFactory中。

    1.4.1.9. onRefresh

    在AbstractApplicationContext中为空方法,在一些web环境下的子类中被重写。

    1.4.1.10. registerListeners

    appctx的ApplicationListener来源有两个:

    • addApplicationListener时添加的ApplicationListener

    • 自己管理的ApplicationListener类型的bean。

    将appctx的application listener添加到appctx的ApplicationEventMulticaster中,使用它发布earlyApplicationEvent(appctx还没有refresh的时候它的publishEvent方法就被调用)。

    1.4.1.11. finishBeanFactoryInitialization

    结束对bean factory的初始化:

    1. 如果bean factory中包含conversion service类型的bean,并且bean name为“conversionService,那么就给bean factory设置conversion service

    2. 如果bean factory没有设置embedded value resolver(StringValueResolver),那么就用一个lambda表达式当它的StringValueResovler,它的功能就是说,根据appctx的environment的resolvePlaceholders方法来解析字符串

    3. 提前实例化所有LoadTimeWeaverAware类型的bean

    4. 设置bean factory的tmpClassLoader为null

    5. 然后冻结bean factory的configuration(DefaultListableBeanFactory)。

    6. 提前实例化bean factory中所有singleton object

    1.4.1.12. finishRefresh

    • clearResourceCaches:DefaultResourceLoader中的方法。

    • initLifecycleProcessor:如果bean factory中有LifecycleProcessor类型的bean并且bean name为“lifecycleProcessor“,就将其取出作为当前app ctx的lifecycleProcessor,否则就使用app ctx内部的bean factory来new一个DefaultLifecycleProcessor,将其作为bean注册到bean factory中,并设置它为appct的lifecycleProcessor。

    • 调用lifecycleProcessor的onRefresh方法。

    • 发布ContextRefreshedEvent

    1.4.1.13. resetCommonCaches

    1.4.2. registerShutdownHook方法

    这个shutdown hook的作用就是在应用退出的时候,调用App Ctx的close方法。

    1.4.3. close方法

    只有当前还是active时,才会close:

    1. CAS设置closed状态位,发布ContextClosedEvent

    2. 调用lifecycle processor的onClose方法

    3. 销毁bean factory中的所有单例bean

    4. 关闭BeanFactory——在子类中重写:

      • 对于GenericApplicationContext来说,只是将持有的BeanFactory的setSerializationId设置为null,依旧持有这个BeanFactory

      • 对于AbstractRefreshableApplicationContext来说,它不仅将BeanFactory的setSerializationId设置为null,而且不再持有改beanfactory

    5. 将applicationListeners恢复到第一次refresh之前的状态

    6. 设置active标记位

    7. 移除shutdown hook

    1.4.4. publishEvent方法

    如果发布的event不是ApplicationEvent,那么包装成PlayloadApplicationEvent。

    如果此时ApplicationContext还没有registerListener,那么将event暂存,否则就将Event通过自己持有的AppliationEventMulticaster发布出去,告知每个ApplicationListner。

    最后将event发布到父级Application Context中(子容器发布的事件被父容器感知,父容器发布的事件子容器不感知)。

    1.5. GenericApplicationContext

    GenericApplicationContext实现了BeanDefinitionRegistry这个接口,这个接口的功能委托给自己持有的DefaultListableBeanFactory(在构造函数中new这个bean factory)。

    GenericApplicationContext还第一次提供了一系列registerBean这个方法,这些方法根据传入的bean类型来构造出ClassDerivedBeanDefinition,然后registerBeanDefinition(BeanDefinitionRegistry中的方法,交给bean factory来实现。)

    GenericApplicationContext继承AbstractApplicationContext,但是它可以设置ResourceLoader。

    如果它设置了ResourceLoader的话,那么它对于ResourceLoader接口中的方法实现交给自己持有的resourceLoader,没有的话才由父类实现。

    对于ResourcePatternResolver中的方法,当它持有的resourceLoader是ResourcePatternResolver时,才委托,否则也是调用父类的同名方法。

    注意:GenericApplicationContext的构造函数中不会调用refresh方法。

    1.6. AnnotationConfigApplicationContext

    AnnotationConfigApplicationContext实现了AnnotationConfigRegistry接口,它持有AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner(在构造函数中根据this创建。),这两个配件是用来从Java Class中读取注解配置来生成bean definition。

    AnnotationConfigRegistry接口定义了两个功能:

    • 扫描给定的package下的Component Class(scan方法)

    • 注册给定的Component Class。(register方法)

    scan方法委托给自己持有ClassPathBeanDefinitionScanner,register方法委托给AnnotatedBeanDefinitionReader。

    重写了AbstractApplicationContext的setEnvironment方法:还将给定的environment设置到AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner中去。

    还又添加了两个配件的设置方法:

    • ScopeMetadataResolver

    • BeanNameGenerator

    这两个配件都是设置到AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner中了。

    重写了GenericApplicationContext引入的registerBean方法,将其最终交给AnnotatedBeanDefinitionReader实现而不是让bean factory来实现。

    注意:构造AnnotationConfigApplicationContext的时候,只有提供class类型或者package名,才会调用register或者scan方法来加载bean definition并调用refresh方法,如果这两者都不提供,那么是不会refresh的,这时需要我们在手动的调用scan或register方法,再手动的refresh

    1.7. AbstractRefreshableApplicationContext

    定义了allowBeanDefinitionOverridingallowCircularReferences这两个参数字段,这两个字段是用来设置自己持有的bean factory的。

    AbstractRefreshableApplicationContext主要是重写了AbstractApplicationContext中的refreshBeanFactory这个方法。

    这个方法在obtainFreshableBeanFactory中的被调用。

    refreshBeanFactory的逻辑是:

    • 销毁旧的bean factory(将其中的单例bean销毁,然后不再持有旧bean factory)

    • 创建带层级的bean factory(DefaultListableBeanFactory,parent bf 从 parent app ctx中来)。

    • 给bean factory设置序列化id为app ctx的id。

    • allowBeanDefinitionOverriding、allowBeanDefinitionOverriding这两个字段如果设置了,设置bean factory

    • 将bean definition加载到bean factory中(在子类中重写)。

    1.8. AbstractRefreshableConfigApplicationContext

    AbstractRefreshableConfigApplicationContext添加了:添加配置文件所在路径的功能,传入的配置文件路径,经过environment的的通配符解析替换之后,保存在一个String数组中。

    然后它同时实现了InitializingBean、BeanNameAware接口。

    • afterPropertiesSet方法中:如果没有active,那么就refresh

    • setBeanName方法中:如果没有设置id,那么就设置id为这个bean name,并且设置display name

    1.9. AbstractXmlApplicationContext

    AbstractXmlApplicationContext主要重写了AbstractRefreshableApplicationContext的loadBeanDefinitions方法。

    使用XmlBeanDefinitionReader来生成bean definition然后注册到bean factory中。

    这些配置来来源有两个:

    • 一是AbstractRefreshableConfigApplicationContext中的配置文件路径数组

    • 二是子类重写的getConfigResources返回的Resource类型的数组。

    1.10. ClassPathXmlApplicationContext

    ClassPathXmlApplicationContext内部又持有了ClassPathResource数组类型作为配置文件的来源。

    注意,在构造ClassPathXmlApplicationContext时,提供了配置路径信息后,才会自动refresh。

  • 相关阅读:
    JavaWeb篇_02——服务器简介及Tomcat服务器简介
    EasyGBS播放器优化:设备通道视频播放出现跳屏问题的修复
    Pointofix ,截屏神器,好用到飞的软件
    【羚珑AI智绘营】分分钟带你拿捏SD中的色彩控制
    【从零开始学习 UVM】2.2、UVM 基础功能 —— UVM utility & field macros(UVM实用宏和字段宏)
    前缀树的实现
    GMV远超预期背后,快手电商做对了什么?
    Hbase原理与实践(学习笔记一:基本概念):
    SpringBoot 2 配置文件 2.5 配置文件分类
    java面试 JDK,JRE,JVM三者的区别
  • 原文地址:https://www.cnblogs.com/stepfortune/p/16340466.html