Bean的加载(下)

5.准备创建bean

一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean;而给我们错觉的函数,比如getObjectFromFactoryBean,其实只是从全局角度去做些统筹的工作。这个规矩对于createBean也不例外。
createBean函数完成的具体步骤及功能:
(1)根据设置的class属性或者根据className来解析Class。
(2)对override属性进行标记及验证。
(3)应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。
(4)创建bean
5.1处理override属性
在Spring配置中存在lookup-method和replace-method两个配置功能,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,这两个功能实现原理其实是在bean实例化的时候如果检测到存在methodOverrides属性,会动态地为当前bean生成代理并使用对应的拦截器为bean做增强处理。
但是对应方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。
5.2实例化的前置处理
在真正调用doCreate方法创建bean的实例前使用了这样一个方法resolveBeforeInstantiation(beanName,mbd)对BeanDefinigiton中的属性做些前置处理。
当经过前置处理后返回的结果如果不为空,那么会直接略过后续的bean的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的AOP功能就是基于这里的判断的。
(1)实例化前的后处理器应用
bean的实例化前调用,也就是将AbsractBeanDefinition转换为BeanWrapper前的处理。给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认为的bean了,而是或许成为了一个经过处理的代理bean,可能是通过cglib生成的,也可能是通过其他技术生成的。
(2)实例化后的后处理器应用
Spring中的规划是在bean的初始化后尽可能保证将注册的后处理器的postProcessAfterInitialization方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法。

6.循环依赖

实例化bean是一个非常复杂的过程,而其中比较难以理解的就是对循环依赖的解决。
6.1.什么是循环依赖
循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。
6.2.Spring如何解决循环依赖
Spring容器循环依赖包括构造器循环依赖和setter循环依赖。Spring中将循环依赖的处理分成了3种情况。
(1)构造器循环依赖
表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。
(2)setter循环依赖
表示通过setter注入方式构成的循环依赖。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean。
(3)prototype范围的依赖处理
对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存“prototype”作用域的bean,因此无法提前暴露一个创建种的bean。
对于“singleton”作用域bean,可以通过“setAllowCircularReferences(false);”来禁用循环引用。

7.创建bean

当经历过resolveBeforeInstantiation方法后,程序有两个选择,如果创建了代理或者说重写了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法并在方法postProcessBeforeInstantiation中改变了bean,则直接返回就可以了,否则需要进行常规bean的创建。而常规bean的创建就是在doCreateBean中完成的。
(1)如果是单例则需要首先清除缓存。
(2)实例化bean,将BeanDefinition转换为BeanWrapper。
转换的大致功能:
·如果存在工厂方法则使用工厂方法进行初始化
·一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数并进行初始化
·如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean的实例化
(3)MergedBeanDefinitionPostProcessor的应用
(4)依赖处理
(5)属性填充。将所有属性填充至bean的实例中。
(6)循环依赖检查
(7)注册DisposableBean
(8)完成创建并返回
7.1 创建bean的实例
(1) 如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置了factory-method,那么Spring会尝试使用instantiateUsingFactoryMethod(beanName,mbd,args)方法根据RootBeanDefinition中配置生成bean的实例。
(2) 解析构造函数并进行构造函数的实例化。因为一个bean对应的类中可能会有多个构造函数,而每个构造函数的参数不同,Spring在根据参数及类型去判断最终会使用哪个构造函数进行实例化。
7.1.1 autowireConstructor
对于实例的创建Spring中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量工作。
autowireConstructor实现的功能考虑了一些几个方面:
(1)构造函数参数的确定
·根据explicitArgs参数判断
·缓存中获取
·配置文件获取
(2)构造函数的确定
(3)根据确定的构造函数转换对应的参数类型
(4)构造函数不确定性的验证
(5)根据实例化策略以及得到的构造函数及构造函数参数实例化Bean。
7.1.2 instantiateBean
带有参数了实例构造中,Spring把精力都放在了构造函数以及参数的匹配上,所以如果没有参数的话那将是非常简单的一件事,直接调用实例化策略进行实例化就可以了。
7.1.3实例化策略
首先判断如果beanDefinition.getMethodOverrides()为空也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方法,快捷简单,但是如果使用了着两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切入近期,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法发时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。
7.2 记录创建bean的ObjectFactory
ObjectFactory的实现:对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPost Processor,其中我们熟知的AOP就是在这里将advice动态织入bean中,若没有则直接返回bean,不做任何处理。
7.3 属性注入
在populateBean函数中提供了这样的处理流程。
(1)InstantiationAwareBeanPostProcessor处理器的postProcessAfterInstantiation函数的应用,此函数可以控制程序是否继续进行属性填充。
(2)根据注入类型(byName,ByType),提取依赖的bean,并统一存入PropertyValues中。
(3)应用InstantiationAwareBeanPostProcessor处理器的postProcessPropertyValues方法,对属性获取完毕填充前对属性的再次处理,典型应用是RequiredAnnotationBeanPostProcessor类中对属性的验证。
(4)将所有propertyValues中的属性填充至BeanWrapper中。
7.3.1 autowireByName
在传入的参数pvs中找出已经加载的bean,并递归实例化,进而加入到pvs中。
7.3.2 autowireByType
实现根据名称自动匹配的第一步就是寻找bw中需要依赖注入的属性,同样对于根据类型自动匹配的实现来讲第一步也是寻找bw中需要依赖注入的属性,然后遍历这些属性并寻找类型匹配的bean,其中最复杂的就是寻找类型匹配的bean。
寻找类型的匹配执行顺序时,首先尝试使用解析器进行解析,如果解析器没有成功解析,那么可能是使用默认的解析器没有做任何处理,或者是使用了自定义的解析器,但是对于集合等类型来说并不在解析范围之内,所以再次对不同类型进行不同情况的处理,虽说对于不同类型处理方式不一致,但是大致的思路还是很相似的。
7.3.3 applyPropertyValues
程序运行到这里,已经完成了对所有注入属性的获取,但是获取的属性是以propertyValues形式存在的,还并没有应用到已经实例化的bean中,这一工作是在applyPropertyValues中。
7.4 初始化bean
Spring中程序已经执行过bean的实例化,并且进行了属性的填充,而就在这时将会调用用户设定的初始化方法。
虽说主要目的是进行客户设定的初始化方法的调用,但是除此之外还有些其他必要的工作
(1)激活Aware
Spring中提供一些Aware相关接口,比如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等,实现这些Aware接口的bean在被初始之后,可以取得一些相应的资源,例如实现BeanFactoryAware的bean在初始后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的bean,在bean被初始后,将会被注入ApplicationContext的实例等。
(2)处理器的应用
在调用客户自定义初始化方法之前以及调用自定义初始化方法后分别会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用户可以根据自己的业务需求进行响应的处理。
(3)激活自定义的init方法
客户定制的初始化方法除了我们熟知的使用配置init-method外,还有使自定义的bean实现InitializingBean接口,并在afterPropertiesSet中实现自己的初始化业务逻辑。
init-method与afterPropertiesSet都是在初始化bean时执行,执行顺序是afterPropertiesSet先执行,而init-method后执行。
在invokeInitMethods方法中就实现了这两个步骤的初始化方法调用。
7.5 注册DisposableBean
Spring中不但提供了对初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,对于销毁方法的扩展,除了我们熟知的配置属性destroy-method方法外,用户还可以注册后处理器DestructionAwareBeanPostProcessor来统一处理bean的销毁方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值