Erlo

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

收藏 2022-06-04 05:00:14   63   博客园
页面报错/反馈
点赞

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。

作者: 迈吉

出处: https://www.cnblogs.com/stepfortune/

关于作者:迈吉

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(showable@qq.com)咨询.

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认