对于第四个步骤,委托给 getObjectFromFactoryBean
方法进行处理不深入分析,但里面有三个方法值得一说:
// 单例操作,前置操作
beforeSingletonCreation(beanName);
try{
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch(Throwable ex){
thrownewBeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally{
// 单例模式,后置操作
afterSingletonCreation(beanName);
}
代码中在类的加载时,有前置操作和后置操作,之前在第一篇笔记看过,很多前置和后置操作都是空方法,等用户自定义扩展用的。
但在这里的不是空方法,在两个方法是用来保存和移除类加载的状态,是用来对循环依赖进行检测的。
同时,这两个方法在不同 scope
加载 bean
时也有使用到,也是个高频方法。
try{
object= postProcessObjectFromFactoryBean(object, beanName);
}
catch(Throwable ex){
thrownewBeanCreationException(beanName,"Post-processing of FactoryBean's object failed", ex);
}
这是一个执行后处理的方法,我接触的不多,先记下概念:
Spring 获取 bean 的规则中有一条:尽可能保证所有 bean 初始化后都会调用注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法进行处理。在实际开发中,可以针对这个特性进行扩展。
获取单例
现在来到时序图中的 1.3 步骤:
// Create bean instance. 创建 bean 实例
// singleton 单例模式(最常使用)
if(mbd.isSingleton()){
// 第二个参数的回调接口,接口是 org.springframework.beans.factory.ObjectFactory#getObject
// 接口实现的方法是 createBean(beanName, mbd, args)
sharedInstance = getSingleton(beanName,()->{
return createBean(beanName, mbd, args);
// 省略了 try / catch
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
来看 getSingleton
方法做了什么:
publicObject getSingleton(String beanName,ObjectFactory<?> singletonFactory){
Assert.notNull(beanName,"Bean name must not be null");
// 注释 4.7 全局变量,加锁
synchronized(this.singletonObjects){
// 检查是否已经被加载了,单例模式就是可以复用已经创建的 bean
Object singletonObject =this.singletonObjects.get(beanName);
if(singletonObject ==null){
// 初始化前操作,校验是否 beanName 是否有别的线程在初始化,并加入初始化状态中
beforeSingletonCreation(beanName);
boolean newSingleton =false;
boolean recordSuppressedExceptions =(this.suppressedExceptions ==null);
if(recordSuppressedExceptions){
this.suppressedExceptions =newLinkedHashSet<>();
}
// 初始化 bean,这个就是刚才的回调接口调用的方法,实际执行的是 createBean 方法
singletonObject = singletonFactory.getObject();
newSingleton =true;
if(recordSuppressedExceptions){
this.suppressedExceptions =null;
}
// 初始化后的操作,移除初始化状态
afterSingletonCreation(beanName);
if(newSingleton){
// 加入缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
来梳理一下流程:
- 检查缓存是否已经加载过
- 没有加载,记录
beanName
的加载状态 - 调用回调接口,实例化
bean
- 加载单例后的处理方法调用:这一步就是移除加载状态
- 将结果记录到缓存并删除加载
bean
过程中所记录到的各种辅助状态
对于第二步和第四步,在前面已经提到,用来记录 bean
的加载状态,是用来对 循环依赖 进行检测的,这里先略过不说。
关键的方法在于第三步,调用了 ObjectFactory
的 getObject()
方法,实际回调接口实现的是 createBean()
方法,需要往下了解,探秘 createBean()
。
准备创建 bean
对于书中,有句话说的很到位:
在
Spring
源码中,一个真正干活的函数其实是以do
开头的,比如doGetBean
、doGEtObjectFromFactoryBean
,而入口函数,比如getObjectFromFactoryBean
,其实是从全局角度去做统筹工作。
有了这个概念后,看之后的 Spring
源码,都知道这个套路,在入口函数了解整体流程,然后重点关注 do
开头的干活方法。
按照这种套路,我们来看这个入口方法 createBean()
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
protectedObject createBean(String beanName,RootBeanDefinition mbd,@NullableObject[] args){
RootBeanDefinition mbdToUse = mbd;
// 有道翻译:确保此时bean类已经被解析,并且克隆 bean 定义,以防动态解析的类不能存储在共享合并 bean 定义中。
// 锁定 class,根据设置的 class 属性或者根据 className 来解析 Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if(resolvedClass !=null&&!mbd.hasBeanClass()&& mbd.getBeanClassName()!=null){
mbdToUse =newRootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 验证及准备覆盖的方法
mbdToUse.prepareMethodOverrides();
// 让 beanPostProcessor 有机会返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if(bean !=null){
// 短路操作,如果代理成功创建 bean 后,直接返回
return bean;
}
// 创建 bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
先来总结这个流程:
- 根据设置的 class 属性或者根据 className 来解析 Class
- 验证及准备覆盖的方法 这个方法是用来处理以下两个配置的:我们在解析默认标签时,会识别
lookup-method
和replaced-method
属性,然后这两个配置的加载将会统一存放在beanDefinition
中的methodOverrides
属性里。 - 应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
- 创建 bean
下面来讲下这几个主要步骤
处理 Override 属性
publicvoid prepareMethodOverrides()throwsBeanDefinitionValidationException{
// Check that lookup methods exists.
if(hasMethodOverrides()){
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
synchronized(overrides){
for(MethodOverride mo : overrides){
// 处理 override 属性
prepareMethodOverride(mo);
}
}
}
}
可以看到,获取类的重载方法列表,然后遍历,一个一个进行处理。具体处理的是 lookup-method
和 replaced-method
属性,这个步骤解析的配置将会存入 beanDefinition
中的 methodOverrides
属性里,是为了待会实例化做准备。
如果 bean
在实例化时,监测到 methodOverrides
属性,会动态地位当前 bean
生成代理,使用对应的拦截器为 bean
做增强处理。
(我是不推荐在业务代码中使用这种方式,定位问题和调用都太麻烦,一不小心就会弄错=-=)
实例化前的前置处理
// 让 beanPostProcessor 有机会返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if(bean !=null){
// 短路操作,如果代理成功创建 bean 后,直接返回
return bean;
}
protectedObject resolveBeforeInstantiation(String beanName,RootBeanDefinition mbd){
Object bean =null;
if(!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)){
// Make sure bean class is actually resolved at this point.
if(!mbd.isSynthetic()&& hasInstantiationAwareBeanPostProcessors()){
Class<?> targetType = determineTargetType(beanName, mbd);
if(targetType !=null){
// 执行前置拦截器的操作
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if(bean !=null){
// 执行后置拦截器的操作
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved =(bean !=null);
}
return bean;
}
在 doCreateBean
方法前,有一个短路操作,如果后处理器成功,将会返回代理的 bean
。
在 resolveBeforeInstantiation
方法中,在确保 bean
信息已经被解析完成,执行了两个关键方法,从注释中看到,一个是前置拦截器的操作,另一个就是后置拦截器的操作。
如果第一个前置拦截器实例化成功,就已经将单例 bean
放入缓存中,它不会再经历普通 bean
的创建过程,没有机会进行后处理器的调用,所以在这里的第二个步骤,就是为了这个 bean
也能应用后处理器的 postProcessAfterInitialization
方法。
创建 bean
终于到了关键的干活方法:doGetBean
。在通过上一个方法校验,没有特定的前置处理,所以它是一个普通 bean
, 常规 bean
进行创建在 doGetBean
方法中完成。
protectedObject doCreateBean(finalString beanName,finalRootBeanDefinition mbd,final@NullableObject[] args){
// Instantiate the bean.
BeanWrapper instanceWrapper =null;
if(mbd.isSingleton()){
instanceWrapper =this.factoryBeanInstanceCache.remove(beanName);
}
if(instanceWrapper ==null){
// 注释 4.8 根据指定 bean 使用对应的策略创建新的实例 例如跟进方法去看,有工厂方法,构造函数自动注入,简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
finalObject bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if(beanType !=NullBean.class){
mbd.resolvedTargetType = beanType;
}
// 允许后处理程序修改合并的bean定义
synchronized(mbd.postProcessingLock){
if(!mbd.postProcessed){
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed =true;
}
}
// 是否需要提前曝光,用来解决循环依赖时使用
boolean earlySingletonExposure =(mbd.isSingleton()&&this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if(earlySingletonExposure){
// 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName,()-> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
// 对 bean 进行填充,将各个属性值注入
// 如果存在对其它 bean 的依赖,将会递归初始化依赖的 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
if(earlySingletonExposure){
Object earlySingletonReference = getSingleton(beanName,false);
// earlySingletonReference 只有在检测到有循环依赖的情况下才 不为空
if(earlySingletonReference !=null){
if(exposedObject == bean){
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
exposedObject = earlySingletonReference;
}
elseif(!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)){
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans =newLinkedHashSet<>(dependentBeans.length);
for(String dependentBean : dependentBeans){
// 检查依赖
if(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)){
actualDependentBeans.add(dependentBean);
}
}
// bean 创建后,它所依赖的 bean 一定是已经创建了
// 在上面已经找到它有依赖的 bean,如果 actualDependentBeans 不为空
// 表示还有依赖的 bean 没有初始化完成,也就是存在循环依赖
if(!actualDependentBeans.isEmpty()){
thrownewBeanCurrentlyInCreationException(beanName);
}
}
}
// Register bean as disposable.
// 根据 scope 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
看到这么长的代码,感觉有点头晕,所以先来梳理这个方法的流程:
- 如果加载的 bean 是单例,要清除缓存
- 实例化 bean,将 BeanDifinition 转化成 BeanWrapper
- 后处理器修改合并后的 bean 定义:bean 合并后的处理,Autowired 注解正式通过此方法实现诸如类型的预解析
- 依赖处理
- 属性填充:将所有属性填充到 bean 的实例中
- 循环依赖检查
- 注册 DisposableBean:这一步是用来处理 destroy-method 属性,在这一步注册,以便在销毁对象时调用。
- 完成创建并返回。
从上面流程可以看出,这个方法做了很多事情,以至于代码超过了 100 多行,给人的阅读体验差,所以尽量还是拆分小方法,在入口方法尽量简洁,说明做的事情,具体在小方法中完成。
因为这个创建过程的代码很多和复杂,我挑重点来理解和学习,详细的还有待深入学习: