spring容器及bean加载机制源码解读

来源:互联网 发布:阿里云搭建微信公众号 编辑:程序博客网 时间:2024/05/21 09:45
转自:http://blog.csdn.net/songyang19871115/article/details/54342242

前言:这是本人第一个博客,早就想记录些总结和理解,可一直不知道从哪开始,最近正好在解决一个spring的问题,正好这个问题涉及到了spring的一些相关基础,整理一下就从这部分开始了。
欢迎所有阅读者和爱好者批评从各个方面(特别是文档和技术方面)批评,指正。互相交流学习。
原想这部分单写一个文章可无奈文笔有限,先放在这吧。

spring的容器加载机制分为提前加载和运行时动态加载,本文通过源码解读容器加载机制和bean加载机制。
1、spring 启动的时候加载
这里写图片描述
(图1.1)
obtainFreshBeanFactory方法中实现了beanFactory的初始化和对配置文件、注解加载。
registerBeanPostProcessors(beanFactory); 方法实现了注册bean自定义初始化(不是类对象实例化)前后的处理器的注册信息。
finishBeanFactoryInitialization 方法是处理提前加载的哪些实例
1.1 spring的配置是怎么样读取的都干了什么
由于篇幅较大这部分使用单独篇幅:http://blog.csdn.net/songyang19871115/article/details/54346444

1.2 spring都提前加载了哪些自带和自定义的bean
这里写图片描述
(图1.2.1)
这里写图片描述
(图1.2.2)

如以上代码(图1.2.1,图1.2.2):应用上下文在启动的时候会自动调用这段代码,这段代码会初始化所有(非懒加载的、单例的、不是抽象的 bean或者SmartFactoryBean)
这里使用了beanDefinitionNames这个集合,这个集合是从配置文件和注解中获取出来的,所有bean的名称。来实现bean的提前加载。

至此 与spring一般的初始化bean,bean工厂,bean 的初始化前置执行器都已经执行完了。

2、spring 动态加载的实现
spring的一切都是为了bean不论是自定义的还是spring自带的,而bean是怎么来的,是什么样的bean都是从getBean开始的,下面揭开他的神秘面纱:
2.1doGetBean的实现:
这里写图片描述
(图2.1.1)
这里写图片描述
(图2.1.2)
这里写图片描述
(图2.1.3)
(图2.1.1,2.1.2,2.1.3为doGetBean的代码实现)
1、如果是单例看看是否在当前容器中。如果单例缓存中没有则查看父容器有没有同名的bean,如果有则返回。说明如果子容器没有这个bean,会从父容器中获取,直到祖先容器都没有。
getObjectForBeanInstance 只是处理如果当前bean是工厂bean的情况
2、获取bean的定义描述信息,如果存在依赖按个递归调用getBean获取依赖的bean,并且注册到当前的bean上
3、如果当前容器和祖先容器都没有则开始创建bean 实例
4、处理bean的转换问题,spring自带conversionService
2.2 createBean的源码实现:
这里写图片描述
(图2.2.1)
这里写图片描述
(图2.2.2)
这里写图片描述
(图2.2.3)
从源码得知,只有bean在创建以前都做了什么,先是查看这个容器中是否含有beanPostProcessors()(这个是由refresh方法调用registerBeanPostProcessors()时候注册进去的)
并且是InstantiationAwareBeanPostProcessor 接口的实现类,如果bean提前实现了,调用beanPostProcessors 的 postProcessAfterInitialization 将用不在调用doCreateBean方法(具体实现如图2.2.2,2.2.3).这块也体现了spring的灵活,连bean的创建都可以定制。

下面说下doCreateBean的创建原理和执行内幕:
这里写图片描述
(图2.2.4)
这里写图片描述
(图2.2.5)
图2.2.4和2.2.5是doCreateBean的实现细节
createBeanInstance中实现了bean的实例的过程,其中包含了构造方法,工厂方法的实例并且放置在beanWrapperImpl中。
populateBean中实现了bean的属性的注入,其中区分了属性的强校验注入等,而且递归调用getBean方法。
registerDisposableBeanIfNecessary 为当前bean的销毁提供策略和实现
initializeBean中的实现下面会详细阐述。

下面详细说下initializeBean方法
这里写图片描述
(图2.2.6)
这个方法并不是对象实例的方法,而是对象实例后的方法。
invokeAwareMethod方法是如果当前的bean是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware 创建bean的时候,会帮你把你需要的数据放进去,但前提一定是三个接口的实现类。
applyBeanPostProcessorsBeforeInitialization 会调用当前容器中所有的BeanPostProcessor 并且执行他们的postProcessBeforeInitialization 方法
invokeInitMethods 是先调用bean的afterPropertiesSet 前提bean是InitializingBean的实现类,然后调用bean 的 initMethod
applyBeanPostProcessorsAfterInitialization 会调用当前容器中所有的BeanPostProcessor 并且执行他们的postProcessAfterInitialization 方法 (这个方法为以后理解代理的相关原理及实现方式埋下伏笔)

至此 springIOC 最核心的提前加载和运行时获取并加载的主要功能及源码解析说完了。 其他的功能请按这个顺序也可不按看源码找到答案,但spring 代码非常庞大并且复杂设计模式用的非常广泛,最好看的抓住核心才能避免事倍功半。
个人理解,虽然有时原理或者实现机制看样子并不能解决碰到的非常复杂问题,但是会为以后解决各种问题及二次开发,打好基本功。

(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;varnumbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append(numbering); for (i = 1; i
    原创粉丝点击