Spring Bean状态(转)
Spring-beans的核心实体是BeanDefinition和BeanFactory。前者映射我们的定义,后者则是依据定义生产bean的工厂。
上图是spring beans的静态结构图,更多是偏重于bean解析,因为1. 理解了bean解析也就理解了一半spring扩展能力;2.BeanFactory的复杂不在于类之间的组织结构,而在于复杂的调用链路,也就没必要是静态结构方面做过多说明。需要说明的是,这只是概念模型,并不完全映射到类,因为spring的抽象层次太高,一个概念实体功能往往由多个类协同完成,画起来比较费劲,就类似BeanFactory,光搞清楚各个BeanFactory之间的关系就理得头痛,所以都尽可能从概念层面说明。
重要实体说明
- DefaultListableBeanFactory是BeanDefintionRegistry的默认实现,它是个适配器,用于适配BeanFactory和BeanDefintionRegistry,工厂和定义通过它统一。它由ApplicationContext初始化,并被作为BeanDefinitionReader的registry。Reader对配置文档加载解析,生成definition并注册到registry–其实就是DefaultListableBeanFactory,这样工厂就拥有了类定义,bean初始化时也可以通过内部方法轻松获取到定义。
- NamespaceHandlerResolver用于获取配置解析实体–NamespaceHandler。它和registry均内聚在上下文实体–ReaderContext中,parser内聚上下文从而可以间接访问handler和registry获得解析和注册的能力。
其他几个实体都比较直观便于理解,不再一一赘述。
整体交互过程
BeanDefinitionReader是整个bean解析的聚合根,它由ApplicationContext创建,并将DefaultListableBeanFactory作为registry传递给它。
BeanDefinitionReader创建文档读取实体–DocuemntReader用于加载解析,并在step3加载文档时创建上下文–ReaderContext传递给文档读取实体。上下文贯穿于整个解析过程始终,它在文档读取实体使用parser解析时也会被传入parser中。
Parse过程是整个加载过程的核心,默认parser通过间接关联的识别器可以依据不同配置节点进行parser切换,当读到非默认配置时,则切换到对应客户化parser解析。解析完成后再通过间接关联的registry进行注册,从而配置定义进入spring管理,待getBean时使用。
客户化配置节点解析
客户化配置是spring非常重要的扩展点,spring强大的扩展能力有一半功能要归功于它,另一半中的80%就是后面要介绍的大名鼎鼎的BeanPostProcessor。不仅仅一些第三方扩展(例如开篇提到的dubbo)基于它,spring本身的很多模块也是基于它,例如spring-aop,spring-context等等,spring体系内除了默认的beans命名空间其余都基于它扩展的。
NamespaceHandlerResolver由BeanDefinitionReader初始化,后者在第一次被访问时读取spring.handlers文件。.handlers文件定义namespace uri和对应处理类的映射关系。例如:
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
上面的这行配置就是配置声明的解析类。
NamespaceHandlerResolver依据节点namespace获得NamespaceHandler,然后使用handler处理自定义配置节点。
public interface NamespaceHandler {
void init();
BeanDefinition parse(Element element, ParserContext parserContext);
BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}
init方法注册localName和自定义parser的关系,parser和localName的关系由handler的提供者自己注册。例如:
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
上面就是aop注册parser的代码片段。config,aspectj-autoproxy这些就是localName,parse过程中不同的localName会切换到不同的parser解析。
spring先通过命名空间定位到handler,handler处理时再基于localName取相应的parser解析当前结点。比如这个配置,aop是命名空间,aspectj-autoproxy是localName。整个读取解析过程中先通过aop找到AopNamespaceHandler,再在解析到aspectj-autoproxy节点时使用AspectJAutoProxyBeanDefinitionParser来解析。如果要研究spring源码,一定要先找到对应parser,知道每个配置项对应到运行时的bean结构才能更好理解spring;而且parser可能会生成一些默认的BeanPostProcessor,如果意识不到这些后处理器,那么对代码的读取将会断片,陷入完全无法理解的境地。比如spring-aop就是由parser默认生成AopAutoProxyCreator这个BeanPostProcessor,在bean初始化后由这个processor对bean生成代理。
Bean获取
上图是getBean过程,整个过程很简洁,实际深入代码会发现非常繁琐。
BeanFactory和BeanDefinitionRegistry在spring里是统一的,参见第一节,图上为了方便理解,拆成两个概念实体。
需要注意的是第4步和第6步,bean配置时可以指定parent属性,如果有parent,则beanFactory会对local和parent做merge,merge的策略是对parent做覆盖,也可以理解为是对parent做继承。这和parent bean factory完全是两个概念,一定要区分开。
在beans的实体静态结构里,分别注明了parent bean definition和parent bean factory。两者都是被关联的,而不是被继承。后者有点像jvm的双亲委托模型,parent和child有各自的上下文,类似于jvm的命名空间。parent bean factory由applicationContext设置,无法配置。比如spring mvc就是两个父子两个容器,在容器refresh时相应的也会把父容器的BeanFactory设置成子容器BeanFactory的parentBeanFactory。
spring bean状态
Bean主要经过instantiate,populate,initializeBean和registerDisposableBean4个状态,在状态流转中会调用很多spring预留的扩展接口。
awareMethod
如果bean继承了BeanFactoryAware,BeanNameAware,BeanClassLoaderAware,则会在initialize阶段将BeanFactory, BeanName和bean ClassLoader设置给Bean。
注意它和ApplicationContextAware是不一样的,后者是由BeanPostProcessor做后处理set的。init method
init method不仅仅包括配置的init-method方法还包括InitializedBean的afterPropertiesSet回调接口,这两者均是无参的,完全可以互相替代,两者中afterPropertiesSet调用在前。
Spring Bean状态(转)的更多相关文章
- (转)Spring Bean Scope 有状态的Bean 无状态的Bean
有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”:一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束.即每个用户最初都会得到一 ...
- Spring bean是如何加载的
Spring bean是如何加载的 加载bean的主要逻辑 在AbstractBeanFactory中doGetBean对加载bean的不同情况进行拆分处理,并做了部分准备工作 具体如下 获取原始be ...
- Spring学习手札(四)谈谈Spring Bean的生命周期及作用域
在Spring中,那些组成应用程序的主体以及由Spring IoC容器所管理的对象,被称之为Bean.Bean与应用程序中其他对象(比如自己创建类)的区别就是,Bean是由IoC容器创建于销毁的.在S ...
- Spring Bean声明周期
Bean的生命周期 理解Spring Bean的生命周期很容易.当一个bean被实例化时,它可能需要执行一些初始化使它转换成可用状态.同样,当bean不再需要,并且从容器中移除时,可能需要做一些清除工 ...
- 第20章-使用JMX管理Spring Bean
Spring对DI的支持是通过在应用中配置bean属性,这是一种非常不错的方法.不过,一旦应用已经部署并且正在运行,单独使用DI并不能帮助我们改变应用的配置.假设我们希望深入了解正在运行的应用并要在运 ...
- Spring 中 ApplicationContext 和 BeanFactory 的区别,以及 Spring bean 作用域
//从ApplicationContext 中取 bean ApplicationContext ac = new ClassPathXmlApplicationContext ( "com ...
- Spring Bean 生命周期之“我从哪里来?” 懂得这个很重要
Spring bean 的生命周期很容易理解.实例化 bean 时,可能需要执行一些初始化以使其进入可用 (Ready for Use)状态.类似地,当不再需要 bean 并将其从容器中移除时,可能需 ...
- Spring Bean 的装配方式
Spring Bean 的装配方式 装配 Bean 的三种方式 一个程序中,许多功能模块都是由多个为了实现相同业务而相互协作的组件构成的.而代码之间的相互联系又势必会带来耦合.耦合是个具有两面性的概念 ...
- Spring bean的作用域以及生命周期
一.request与session的区别 request简介 request范围较小一些,只是一个请求. request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请 ...
随机推荐
- hexo干货系列:(六)hexo提交搜索引擎(百度+谷歌)
前言 能看到这里,说明大家都跟我一样,已经把博客搭起来并洋洋洒洒写了几篇博文,正春风得意感觉良好的时候,搭建博客有屎以来最大的危机出现在没有准备的我面前,百度+谷歌都无法搜索到我的博客.装逼还没几天就 ...
- HDU-1041-Computer Transformation,大数递推,水过~~
Computer Transformatio ...
- Go 方法和接收者
package main import ( "fmt" ) //面向对象 //go仅支持封装,不支持继承和多态 //go语言中没有class,只要struct //不论地址还是结构 ...
- 【Dijstra堆优化】HDU 3986 Harry Potter and the Final Battle
http://acm.hdu.edu.cn/showproblem.php?pid=3986 [题意] 给定一个有重边的无向图,T=20,n<=1000,m<=5000 删去一条边,使得1 ...
- bzoj 1702 贪心,前缀和
[Usaco2007 Mar]Gold Balanced Lineup 平衡的队列 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 807 Solved: ...
- 解决Genymotion不能安装软件的问题
解决Genymotion不能安装软件的问题 官方取消了with google apps字样的rom,导致安装app不兼容的解决 有些童鞋在兴奋的打开Genymotion模拟器后可能会发现无法安装下载下 ...
- 2017"百度之星"程序设计大赛 - 初赛(A)数据分割
n<=100000条相等/不等关系描述<=100000个数,把这些数据分割成若干段使得每一段描述都出现冲突且冲突只出现在最后一行. 相等关系具有传递性,并查集维护:不等关系根据相等关系进行 ...
- 洛谷——P1262 间谍网络
P1262 间谍网络 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意 ...
- windows上安装mysql
安装mysql后 命令行闪退 查看服务 也没有MySQL服务启动 你安装了mysql没有,没有就先安装,安装好mysql以后,在bin目录下有个mysqld.exe,运行这个程序就可以添加mysql服 ...
- Office PDF如何批量删除书签
网上下了本PDF,不知道哪个傻逼每一页都做了一个书签,我真的想做个书签,看看自己做到哪一页都被搞乱了.狗日的,还没有批量删除功能. 方法就是,你定位到任意一个书签,然后按住Delete键,然后就可 ...