Spring IOC源码研究笔记——ApplicationContext系列

1. Spring IOC源码研究笔记——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最重要的方法了,它定义了

Spring IOC源码研究笔记——ApplicationContext系列_第1张图片

1.4.1.1. prepareRefresh

一个ConfigurableApplicationContext可能被refresh多次:

做了三件事:

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

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

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

Spring IOC源码研究笔记——ApplicationContext系列_第2张图片

1.4.1.2. obtainFreshableBeanFactory

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

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

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

Spring IOC源码研究笔记——ApplicationContext系列_第3张图片

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

Spring IOC源码研究笔记——ApplicationContext系列_第4张图片

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(将其放在最后)。

Spring IOC源码研究笔记——ApplicationContext系列_第5张图片

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中。

Spring IOC源码研究笔记——ApplicationContext系列_第6张图片

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中。

Spring IOC源码研究笔记——ApplicationContext系列_第7张图片

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方法就被调用)。

Spring IOC源码研究笔记——ApplicationContext系列_第8张图片

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

Spring IOC源码研究笔记——ApplicationContext系列_第9张图片

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方法。

Spring IOC源码研究笔记——ApplicationContext系列_第10张图片

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

Spring IOC源码研究笔记——ApplicationContext系列_第11张图片

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

定义了 allowBeanDefinitionOverriding 、 allowCircularReferences 这两个参数字段,这两个字段是用来设置自己持有的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中(在子类中重写)。

Spring IOC源码研究笔记——ApplicationContext系列_第12张图片

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类型的数组。

Spring IOC源码研究笔记——ApplicationContext系列_第13张图片

1.10. ClassPathXmlApplicationContext

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

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

你可能感兴趣的:(spring,java,后端)