Bean的加载(上)

对于加载bean的功能,在Spring中的调用方式为:
MyTestBean bean = (MyTestBean) bf.getBean(“myTestBean”)
Spring加载bean的过程中所涉及的步骤大致如下:
(1)转换对应beanName
这里对传入的参数可能是别名,也可能是FactoryBean,所以需要进行一些列解析,这些解析内容包括如下内容:
·去除FactoryBean的修饰符,也就是如果name=“&aa”,那么会首先去除&而使name=“aa”。
·取指定alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B;若别名A指向别名B,别名B又指向名称为C的bean则返回C。
(2)尝试从缓存中加载单例
首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完成就会将创建的bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory。
(3)bean的实例化
如果从缓存中得到bean的原始状态,则需要对bean进行实例化。缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的。
(4)原型模式的依赖检查
只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentlyInCreation(beanName)判断true。
(5)检测parentBeanFactory
parentBeanFactory如果为空,则其他一切都是浮云,但是!containsBeanDefinition(beanName)就比较重要了,它是在检测如果当前加载的XML配置文件中不包含beanName所对应的配置,只能到parentBeanFactory去尝试下了,然后再去递归的调用getBean方法
(6)将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition
因为从XML配置文件中读取到的bean信息是存储在GernericBeanDefinition中的,但是所有的bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性。
(7)寻找依赖
因为bean的初始化过程中可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring的加载顺寻中,在初始化某个bean的时候首先会初始化这个bean所对应的依赖。
(8)针对不同的scope进行bean的创建
在Spring中存在着不同的scope,其中默认的是singleton,但是还有些其他的配置诸如prototype、request之类的。在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。
(9)类型转换
程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型。

1.FactoryBean的使用

FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式。
在该接口中还定义了以下3个方法:
·T getObject():返回由FactoryBean创建的bean实例,如果isSingleton()返回ture,则该实例会放到Spring容器中单实例缓存池中。
·boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
·Class getObjectType():返回FactoryBean创建的bean实例

2.缓存中获取单例bean

单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory。
这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是再allowEarlyReference为true的情况下才会使用。
·singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name --> bean instance
·singletonFactories:用于保存BeanName和创建bean的工厂之间的关系,bean name --> ObjectFactory。
earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用。
registeredSingletons:用来保存当前所有已注册的bean。

3.从bean的实例中获取对象

在getBean方法中,getObjectForBeanInstance是个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中断getObject()作为返回值。
其实这个方法并没有什么重要的信息,大多是些辅助代码以及一些功能性判断,而真正的核心代码却委托给了getObjectFromFactoryBean,getObjectFromFactoryBean中所做的工作:
·对FactoryBean正确性的验证。
·对非FactoryBean不做任何处理。
·对bean进行转换
·将从Factory中解析bean的工作委托给getObjectFromFactoryBean。
Spring获取bean的规则中有这样一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

4.获取单例

如果缓存中不存在已经加载的单例bean就需要从头开始bean的加载过程了,而Spring中使用getSingleton的重载方法实现bean的加载过程。
getSingleton中其实是使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例bean的方法其实并不是在getSingleton中实现的秒其实现逻辑是在ObjectFactory类型的singletonFactory中实现的。而这些准备及处理操作包括如下内容:
(1)检查缓存是否已经加载过
(2)若没有加载,则记录beanName的正在加载状态。
(3)加载单例前记录加载状态。也就是通过this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测。
(4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean。
(5)加载单例后的处理方法调用。当bean加载结束后需要移除缓存中对该bean的正在加载状态的记录。
(6)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态。
返回处理结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值