非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
继承自ApplicationContext、LifeCycle、Closable。
-
添加了一些配置的功能:
-
设置id
-
设置parent app ctx
-
设置、获取environment
-
设置class loader
-
添加protocol resolver(来自DefaultResourceLoader)
-
添加bean factory post processor
-
添加application listener
-
-
然后是涉及生命周期的一些方法:
-
refresh
-
close
-
添加shutdown hook
-
判断是否active
-
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。)
refreshBeanFactory是个抽象方法,在子类中实现。
-
对于GenericApplicationContext来说,它的构造函数中就将DefaultListableBeanFactory给new出来了,并持有它,refreshBeanFactory只是给它设置id、以及设置标记位。
-
对于AbstractRefreshableApplicationContext来说:它销毁旧bean factory,然后创建一个新的bean factory,设置id后,就从xml文件中加载bean definition。
对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中。
在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):
-
遍历传入的bean factory post processor,将其中的bean definition registry post processor和一般的bean factory post processor分开,并用其中的bean definition registry post processor的postProcessBeanDefinitionRegistry方法处理app ctx的bean factory
-
然后再从app ctx的bean factory中取出所有PriorityOrdered类型的bean definition registry post processor类型的bean,排序后,用其postProcessBeanDefinitionRegistry方法依次处理app ctx的bean factory,并将其保存下来以供去重。
-
然后再从app ctx的bean factory中取出所有只是Ordered类型的没用过的bean definition registry post processor类型的bean,排序后,用其postProcessBeanDefinitionRegistry方法依次处理app ctx的bean factory,并将其保存下来以供去重。
-
然后再取出剩下的普通优先级的没用过的bean definition registry post processor,用其postProcessBeanDefinitionRegistry方法r处理app ctx的bean factory。注意由于postProcessBeanDefinitionRegistry时可能会向bean factory中注册新的bean definition registry post processor类型的bean,因此用广度优先的方式进行不断的迭代,直到没有为止。
-
将上面的这些bean definition registry post processor按照同样的顺序,使用其postProcessBeanFactory方法来处理bean factory
-
将入参中的bean factory post processor的postProcessBeanFactory方法处理bean factory。
-
-
如果bean factory没有实现BeanDefinitionRegistry接口(基本不可能走这里):
- 遍历入参中的bean factory post processor来postProcessBeanFactory。
最后取出BeanFactory中的BeanFactoryPostProcessor类型并且没用过的Bean,按照PriorityOrdered -> Ordered -> Regular优先级的顺序对BeanFactory进行后处理。
注意:
-
对于PriorityOrdered、Ordered优先级的后处理器,它们在处理前都需要进行排序,而regular优先级的不用排序。
-
对BDRPP和BFPP的处理不相同,BDRPP在后处理时可能引入新的BDRPP,因此采用广度优先搜索的方式,需要多次遍历Bean Factory中的BDRPP。而BFPP,直接遍历一次Bean Factory中的BFPP,不进行广度优先搜索。
-
上面的排序,一般使用AnnotationAwareOrderComparator来排序:实现了PriorityOrdered -> 实现了Ordered -> Spring的@Order -> javax的@Priority
整体的顺序为:
-
非bean方式的BDRPP先postProcessBeanDefinitionRegistry
-
bean方式的并且是PriorityOrdered的BDRPP,排序后,postProcessBeanDefinitionRegistry
-
bean方式的并且是Ordered的BDRPP,排序后,postProcessBeanDefinitionRegistry
-
bean方式的非Ordered的BDRPP,postProcessBeanDefinitionRegistry
-
上面的BDRPP,相同顺序来postProcessBeanFactory
-
非bean方式的BDRPP,postProcessBeanFactory
-
bean方式的并且是PriorityOrdered的BFPP,排序后,postProcessBeanFactory
-
bean方式的并且是Ordered的BFPP,排序后,postProcessBeanFactory
-
bean方式的非Ordered的BFPP,postProcessBeanFactory
由于方法太长,委托给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(将其放在最后)。
如果本地beanfactory中没有messageSource这个bean,那么new一个DelegatingMessageSource设置好它的parent后(DelegatingMessageSource是HierachicalMessageSource,这个parent要么是当前app ctx的父app ctx内部的MessageSource,要么就是父app ctx),交给application context,同时将其作为单例注册到bean factory中。
1.4.1.8. initApplicationEventMulticasterApplicationContext实现了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. registerListenersappctx的ApplicationListener来源有两个:
-
addApplicationListener时添加的ApplicationListener
-
自己管理的ApplicationListener类型的bean。
将appctx的application listener添加到appctx的ApplicationEventMulticaster中,使用它发布earlyApplicationEvent(appctx还没有refresh的时候它的publishEvent方法就被调用)。
1.4.1.11. finishBeanFactoryInitialization结束对bean factory的初始化:
-
如果bean factory中包含conversion service类型的bean,并且bean name为“conversionService,那么就给bean factory设置conversion service
-
如果bean factory没有设置embedded value resolver(StringValueResolver),那么就用一个lambda表达式当它的StringValueResovler,它的功能就是说,根据appctx的environment的
resolvePlaceholders
方法来解析字符串 -
提前实例化所有LoadTimeWeaverAware类型的bean
-
设置bean factory的tmpClassLoader为null
-
然后冻结bean factory的configuration(DefaultListableBeanFactory)。
-
提前实例化bean factory中所有singleton object
-
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
这个shutdown hook的作用就是在应用退出的时候,调用App Ctx的close方法。
1.4.3. close方法只有当前还是active时,才会close:
-
CAS设置closed状态位,发布ContextClosedEvent
-
调用lifecycle processor的onClose方法
-
销毁bean factory中的所有单例bean
-
关闭BeanFactory——在子类中重写:
-
对于GenericApplicationContext来说,只是将持有的BeanFactory的setSerializationId设置为null,依旧持有这个BeanFactory
-
对于AbstractRefreshableApplicationContext来说,它不仅将BeanFactory的setSerializationId设置为null,而且不再持有改beanfactory
-
-
将applicationListeners恢复到第一次refresh之前的状态
-
设置active标记位
-
移除shutdown hook
如果发布的event不是ApplicationEvent,那么包装成PlayloadApplicationEvent。
如果此时ApplicationContext还没有registerListener,那么将event暂存,否则就将Event通过自己持有的AppliationEventMulticaster发布出去,告知每个ApplicationListner。
最后将event发布到父级Application Context中(子容器发布的事件被父容器感知,父容器发布的事件子容器不感知)。
1.5. GenericApplicationContextGenericApplicationContext实现了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. AnnotationConfigApplicationContextAnnotationConfigApplicationContext实现了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中(在子类中重写)。
AbstractRefreshableConfigApplicationContext添加了:添加配置文件所在路径的功能,传入的配置文件路径,经过environment的的通配符解析替换之后,保存在一个String数组中。
然后它同时实现了InitializingBean、BeanNameAware接口。
-
afterPropertiesSet方法中:如果没有active,那么就refresh
-
setBeanName方法中:如果没有设置id,那么就设置id为这个bean name,并且设置display name
AbstractXmlApplicationContext主要重写了AbstractRefreshableApplicationContext的loadBeanDefinitions方法。
使用XmlBeanDefinitionReader来生成bean definition然后注册到bean factory中。
这些配置来来源有两个:
-
一是AbstractRefreshableConfigApplicationContext中的配置文件路径数组
-
二是子类重写的getConfigResources返回的Resource类型的数组。
ClassPathXmlApplicationContext内部又持有了ClassPathResource数组类型作为配置文件的来源。
注意,在构造ClassPathXmlApplicationContext时,提供了配置路径信息后,才会自动refresh。