Spring Bean的生命周期
Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解Spring Bean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是 ApplicationContext中Bean的生命周期。而实际上BeanFactory也是差不多的,只不过处理器需要手动注册。
前言
Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解Spring Bean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是 ApplicationContext中Bean的生命周期。而实际上BeanFactory也是差不多的,只不过处理器需要手动注册。 – 这段话系摘抄
一直以来都很想总结一份Spring Bean的生命周期序列图来, 趁最近有时间, 画一份。
此处以Web为例
可以直接看UML图1
Spring Bean结构
BeanFactoryPostProcessor
BeanFactoryPostProcessor
是Spring中一个优先级较高的Bean, 它主要负责处理一些系统启动所需的依赖。
下图描述了系统对它的初始化流程,优先级自上而下:2可以直接看UML图3
可以看出, 一般使用到BeanFactoryPostProcessor的有配置文件的加载、mybatis的扫包、以及在代码里面写死的一些扫包路径等。
它们的初始化优先级最高、最先被Spring初始化。
BeanPostProcessor
BeanPostProcessor
是Spring架构设计"开闭原则"中的一环。"依赖注入"便是依赖这个接口实现的。
这个接口有不少子类。比如
InstantiationAwareBeanPostProcessor
子类负责依赖注入(@Resource
、@Value
等)可见 Spring PropertySourcesPlaceholderConfigurer工作原理DestructionAwareBeanPostProcessor
负责处理@PostConstruct
和@PreDestroy
注解。这里只记录了用户相关性比较大的, 框架相关(如
MergedBeanDefinitionPostProcessor
)的不做介绍
优先级自上而下:4
可以直接看UML图5
序列图
Spring生命周期 之 Spring的载入
Spring的载入依赖于web.xml配置。依赖于 Java Servlet 之 Filter
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
一般情况下,还会加上配置文件,即:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
Spring Context基本流程为:
Spring Context的初始化依赖于Java Servlet流程。可参考ServletContext作用功能详解 文章。
- Spring依赖于Servlet Context 创建WebApplicationContext。
- 创建BeanFactory。
- 解析Spring XML填充BeanFactory(
BeanDefinitionParserDelegate
)。 - 完成Spring载入。
Spring对xml标签的解析是通过NamespaceHandler来实现的。需要被Spring识别,则必须将所需文件放在
${CLASSPATH}/META-INF
下。其中
spring.tooling
记录schemas信息,
spring.schemas
记录xsd存放位置
spring.handlers
记录NamespaceHandler类的路径。
例如:
http://www.springframework.org/schema/context
这个schemas使用ContextNamespaceHandler
来代理解析,其下的<context:component-scan base-package="**" />
标签则对应着ComponentScanBeanDefinitionParser
这个解析器。它的作用就是进行全局扫包。
Spring的载入流程,起始于Servlet, 终止与 org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
。
整个流程通过对xml文件的解析实现如:
context:component-scan
扫包功能import
将一个xml拆分成多个xmlbean
定义一个Spring Beandubbo:provider
自定义标签等功能
Spring的生命周期跟Spring Bean的生命周期是不一样的。
Spring生命周期 之 Spring的整体流程
Spring 后续流程在类
AbstractApplicationContext
中。
起始于#postProcessBeanFactory
。
下面有一段源码解析。 这段源码解析里面的大部分功能需要“Spring Bean生命周期”去支持
// 对Web Spring而言, 这儿注册了个BeanPostProcessor.
// 这步很重要, 因为后续的BeanFactoryPostProcessor的实例类需要这个做预处理
postProcessBeanFactory(beanFactory);
// 在此处通过PostProcessorRegistrationDelegate对BeanFactoryPostProcessor进行初始化.
// 在 Spring载入流程中 通过扫包(component-scan)、 自定义标签(<bean />)等方式获取到的BeanFactoryPostProcessor,将会在这儿进行初始化。
// 一般令人喜闻乐见的PropertySourcesPlaceholderConfigurer就是在这儿进行初始化的。它会将配置文件切分成kv形式的Properties。在后续流程中使用。
// BeanFactoryPostProcessor也是Spring Bean, 也遵守与Spring生命周期的规则。
// BeanFactoryPostProcessor不仅被初始化,还被执行了postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(beanFactory);
// 在此处通过PostProcessorRegistrationDelegate对BeanPostProcessor等进行初始化.
// 流程很简单,将BeanPostProcessor加入预备列表. 用于贯穿Spring Bean的生命周期
// TODO 比如包含@Resource、@Value等非配置类注解的Bean, 就会通过BeanPostProcessor对它们进行赋值。
// BeanPostProcessor仅仅被初始化,没有执行它的方法(它本就是给别的类用的)
registerBeanPostProcessors(beanFactory);
// 配置国际化操作(如果有相关bean)
initMessageSource();
// 指定SimpleApplicationEventMulticaster作为系统观察者
// 可见ApplicationEventPublisherAware, ApplicationEvent
initApplicationEventMulticaster();
// 对web而言,这里主要是注册一个ThemeSource。
// 使用jsp的时候会体现出一些页面颜色的变换。
onRefresh();
// 在initApplicationEventMulticaster()中注册了观察者, 在此处为观察者添加被观察者。
// 在这里观察者们就可以接受Context消息了。
registerListeners();
// 这里是对所有剩余Bean(non-lazy-init)的初始化
// 也是Spring初始化的很关键一步。
finishBeanFactoryInitialization(beanFactory);
// 此处开启了Spring的生命周期
// 事件也可以开始被发送
finishRefresh();
见下图。
这张图是对Spring生命周期的部分描述。
如上
Spring Bean生命周期 之 初始化
Spring Bean生命周期初始化 如下图所示(只介绍单例、只介绍用户相关):
其中InstantiationAwareBeanPostProcessor是BeanPostProcessor子类 6
BeanPostProcessor的执行顺序可见源码7
如下图
可以直接看UML图8
如上
解析:
- Spring的初始化离不开Spring Bean的初始化。
- 每个Spring托管的Bean都必须经历Spring Bean初始化这个流程,
BeanFactoryPostProcessor
也不例外- 在初始化
BeanFactoryPostProcessor
之前预先初始化了数个BeanPostProcessor
- 自定义的
BeanPostProcessor
之所以没有被执行是因为那个时候它们都还没有被初始化
- 在初始化
BeanPostProcessor
相当于是一个Spring的拓展功能,用户可以通过它对Bean做定制化处理- Spring的
@Value
,@Resource
等也是通过BeanPostProcessor
注入的,也是在Bean生命周期的’初始化’中注入的 - 在
BeanPostProcessor#postProcessAfterInitialization
执行完毕之后Bean的初始化流程就已经完毕,就可以开始执行业务逻辑了。 - 用户的拓展性
- 用户希望对Bean做侵入性修改,可以实现
BeanPostProcessor
或者其子类 - 用户希望在Bean载入前自定义自己的用户数据,比如配置载入,可以实现
BeanFactoryPostProcessor
或者其子类 - 用户希望对Spring Context做到感知,可以实现
Aware
接口ApplicationContextAware
会注入给你当前ApplicationContext
BeanFactoryAware
会注入给你当前BeanFactory
BeanClassLoaderAware
会注入给你加载当前系统Bean的ClassLoader
- …
- 用户希望在属性注入后做一些用户类的初始化操作,可以实现
InitializingBean
接口 - …
- 用户希望对Bean做侵入性修改,可以实现
- Spring Bean初始化生命周期中还有很多其余的操作, 但是大部分都是系统相关的,用户无感知,因此没有做介绍。
附加:Spring事务实现原理
Spring IOC 控制逻辑
Spring 代理/事务实现流程图
Spring 事务实现小逻辑
其中, 类拦截器(各个代理组件)是循环嵌套的, 比如处理异常的, 和处理事务的, 两者是循环嵌套, 且相互兼容的。
附录
附录一 BeanFactoryPostProcessor UML
BeanFactoryPostProcessor的UML图
附录二 Spring Context UML
Spring Context 的UML图
附录三 BeanPostProcessor UML
BeanPostProcessor 的UML图
附录四 Spring Bean初始化 UML
Spring Bean初始化的UML图
附录五 Autowire/Resource/Value等注解
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
用于处理Javax所提供的规范,包括:
- 注入:
WebServiceRef
、EJB
、Resource
等。 - 起始、结束方法:
@PostConstruct
、@PreDestroy
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
用于处理Spring定义的注入规范,如:
- 配置、Bean注入:
@Autowired
、@Value
、@Inject
等 - 同时支持Javax定义的注入优先级:
@Priority
, Spring定义的@Primary
(比Priority高优)
注解
InstantiationAwareBeanPostProcessor的方法执行见AbstractAutowireCapableBeanFactory
Spring Context 的UML图见附录二 ↩︎
BeanDefinitionRegistryPostProcessor
是BeanFactoryPostProcessor
的一个子接口;PriorityOrdered.class
与Ordered.class
是接口类。 ↩︎BeanFactoryPostProcessor
的UML图见附录一 ↩︎BeanPostProcessor
跟BeanFactoryPostProcessor
的初始化方式不一样,它在初始化的时候并不会执行接口里面的方法,只是简单的初始化这个类。BeanPostProcessor的执行是针对所有Spring Bean而言的,一些自定义BeanPostProcessor对BeanFactoryPostProcessor无效是因为那时还没被初始化。 ↩︎BeanPostProcessor的UML图见附录三 ↩︎
- ↩︎
见图(AbstractAutowireCapableBeanFactory)
↩︎Spring Bean 初始化的UML图见附录四。 ↩︎
更多推荐
所有评论(0)