创建 bean 的实例
在上面第二个步骤,做的是实例化 bean
,然后返回 BeanWrapper
protectedBeanWrapper createBeanInstance(String beanName,RootBeanDefinition mbd,Object[] args){
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
// Shortcut when re-creating the same bean...
boolean resolved =false;
boolean autowireNecessary =false;
if(args ==null){
synchronized(mbd.constructorArgumentLock){
// 如果一个类有多个构造函数,每个构造函数都有不同的参数,调用前需要进行判断对应的构造函数或者工厂方法
if(mbd.resolvedConstructorOrFactoryMethod !=null){
resolved =true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 如果已经解析过,不需要再次解析
if(resolved){
if(autowireNecessary){
// 实际解析的是 org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
// 构造函数自动注入(如果参数有很多个,在匹配构造函数可复杂了,不敢细看=-=)
return autowireConstructor(beanName, mbd,null,null);
}
else{
// 使用默认的构造函数
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring? 需要根据参数解析构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if(ctors !=null|| mbd.getResolvedAutowireMode()== AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues()||!ObjectUtils.isEmpty(args)){
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if(ctors !=null){
// 构造函数注入
return autowireConstructor(beanName, mbd, ctors,null);
}
// No special handling: simply use no-arg constructor. 没有特殊的处理,使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
大致介绍功能:
- 如果存在工厂方法则使用工厂方法进行初始化
- 一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数进行 bean 的实例化:在这一步我是真心服,为了匹配到特定的构造函数,下了很大的功夫,感兴趣的可以定位到这个函数观看
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor
- 如果即不存在工厂方法,也不存在带有参数的构造函数,会使用默认的构造函数进行 bean 的实例化
在这个流程中,通过两种方式,一种是工厂方法,另一种就是构造函数,将传进来的 RootBeanDefinition
中的配置二选一生成 bean
实例
具体的不往下跟踪,来看下一个步骤
处理循环依赖
// 是否需要提前曝光,用来解决循环依赖时使用
boolean earlySingletonExposure =(mbd.isSingleton()&&this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if(earlySingletonExposure){
// 第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName,()-> getEarlyBeanReference(beanName, mbd, bean));
}
关键方法是 addSingletonFactory
,完成的作用:在 bean
初始化完成前将创建实例的 ObjectFactory
加入单例工厂
一开始就讲过, ObjectFactory
是创建对象时使用的工厂。在对象实例化时,会判断自己依赖的对象是否已经创建好了,判断的依据是查看依赖对象的 ObjectFactory
是否在单例缓存中,如果没有创建将会先创建依赖的对象,然后将 ObjectFactory
放入单例缓存。
这时如果有循环依赖,需要提前对它进行暴露,让依赖方找到并正常实例化。
循环依赖解决方案在下一篇再细讲吧。
属性注入
这也是个高频方法,在初始化的时候要对属性 property
进行注入,贴一些代码片段:
populateBean(beanName, mbd, instanceWrapper);
protectedvoid populateBean(String beanName,RootBeanDefinition mbd,@NullableBeanWrapper bw){
// 给 awareBeanPostProcessor 后处理器最后一次机会,在属性设置之前修改bean的属性
boolean continueWithPropertyPopulation =true;
if(!mbd.isSynthetic()&& hasInstantiationAwareBeanPostProcessors()){
...
if(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)){
continueWithPropertyPopulation =false;
break;
}
...
}
PropertyValues pvs =(mbd.hasPropertyValues()? mbd.getPropertyValues():null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if(resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE){
MutablePropertyValues newPvs =newMutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if(resolvedAutowireMode == AUTOWIRE_BY_NAME){
// 根据名字自动注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if(resolvedAutowireMode == AUTOWIRE_BY_TYPE){
// 根据类型自动注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 后处理器已经初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 需要依赖检查
boolean needsDepCheck =(mbd.getDependencyCheck()!=AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds =null;
// 从 beanPostProcessors 对象中提取 BeanPostProcessor 结果集,遍历后处理器
for(BeanPostProcessor bp : getBeanPostProcessors()){
...
}
// 在前面也出现过,用来进行依赖检查
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
// 将属性应用到 bean 中,使用深拷贝,将子类的属性一并拷贝
applyPropertyValues(beanName, mbd, bw, pvs);
}
由于代码太长,感兴趣的小伙伴定位到 注释 4.11 位置查看吧
介绍一下处理流程:
- 调用
InstantiationAwareBeanPostProcessor
处理器的postProcessAfterInstantiation
方法,判断控制程序是否继续进行属性填充 - 根据注入类型(
byName/byType
),提取依赖的bean
,统一存入PropertyValues
中 - 判断是否需要进行
BeanPostProcessor
和 依赖检查:
- 如果有后处理器,将会应用
InstantiationAwareBeanPostProcessor
处理器的postProcessProperties
方法,对属性获取完毕填充前,对属性进行再次处理。 - 使用
checkDependencies
方法来进行依赖检查
- 将所有解析到的
PropertyValues
中的属性填充至BeanWrapper
中。
在这个方法中,根据不同的注入类型进行属性填充,然后调用后处理器进行处理,最终将属性应用到 bean
中。
这里也不细说,继续往下走,看下一个方法
初始化 bean
在配置文件中,在使用 <bean>
标签时,使用到了 init-method
属性,这个属性的作用就是在这个地方使用的:bean
实例化前,调用 init-method
指定的方法来根据用户业务进行相应的实例化。来看下入口方法 initializeBean
:
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
protectedObject initializeBean(finalString beanName,finalObject bean,@NullableRootBeanDefinition mbd){
// 注释 4.12 securityManage 是啥,不确定=-=
if(System.getSecurityManager()!=null){
AccessController.doPrivileged((PrivilegedAction<Object>)()->{
invokeAwareMethods(beanName, bean);
returnnull;
}, getAccessControlContext());
}
else{
// 如果没有 securityManage,方法里面校验了 bean 的类型,需要引用 Aware 接口
// 对特殊的 bean 处理:Aware/ BeanClassLoader / BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if(mbd ==null||!mbd.isSynthetic()){
// 熟悉么,后处理器又来了
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 激活用户自定义的 init-method 方法
invokeInitMethods(beanName, wrappedBean, mbd);
if(mbd ==null||!mbd.isSynthetic()){
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这个方法主要是用来进行我们设定的初始化方法的调用,不过在方法内部,还做了其它操作,所以一起来讲下流程:
1、激活 Aware 方法
Spring
中提供了一些 Aware
接口,实现了这个接口的 bean
,在被初始化之后,可以取得一些相对应的资源,例如 BeanFactoryAware
,在初始化后, Spring
容器将会注入 BeanFactory
的实例。所以如果需要获取这些资源,请引用 Aware
接口。
2、执行后处理器
相信这个大家已经不陌生了,我们可以在诸如 PostProcessor
等后处理器里面自定义,实现修改和扩展。例如 BeanPostProcessor
类中有 postProcessBeforeInitialization
和 postProcessAfterInitialization
,可以对 bean
加载前后进行逻辑扩展,可以将它理解成切面 AOP
的思想。
3、激活自定义的 init 方法
这个方法用途很明显,就是找到用户自定义的构造函数,然后调用它。要注意的是,如果 bean
是 InitializingBean
类型话,需要调用 afterPropertiesSet
方法。
执行顺序是先 afterPropertiesSet
,接着才是 init-method
定义的方法。
注册 disposableBean
这是 Spring
提供销毁方法的扩展入口, Spring
爸爸将我们能考虑和想扩展的口子都给预留好。除了通过 destroy-method
属性配置销毁方法外,还可以注册后处理器 DestructionAwareBeanPostProcessor
来统一处理 bean
的销毁方法:
protectedvoid registerDisposableBeanIfNecessary(String beanName,Object bean,RootBeanDefinition mbd){
AccessControlContext acc =(System.getSecurityManager()!=null? getAccessControlContext():null);
if(!mbd.isPrototype()&& requiresDestruction(bean, mbd)){
if(mbd.isSingleton()){
// 单例模式
// 注册 DisposableBean
registerDisposableBean(beanName,
newDisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else{
// A bean with a custom scope...
Scope scope =this.scopes.get(mbd.getScope());
scope.registerDestructionCallback(beanName,
newDisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
这里就是往不同的 scope
下, 进行 disposableBean
的注册。
总结
本篇笔记总结了类加载的过程,结合时序图和代码分析,希望对它能有一个更深的了解。
同时对代码编写也有一点感触:
- 不要写过长的方法,尽量拆分成小方法,清晰意图
从一开始看 Spring
源码的时候,就惊叹于它代码的整洁和逻辑清晰,入口方法展示也要做的事情,然后工作具体逻辑细分,体现了代码设计者的高超设计,所以在看到有几个方法超过 100 行,心中小小吐槽了一下,看来我跟大佬们写的代码也有共同点,那就是还可以进行优化~
- 要在关键地方都打上日志,方便排查和定位
我截取的代码片段,为了篇幅原因,有些逻辑判断和日志处理都给摘掉,但是日志管理是很重要的一环,在关键地方打印日志,在之后排查问题和分析问题会有帮助。不然如果懒得打印日志,在关键的地方没有打印日志,即便出现了问题,也不知道从何查起,导致问题迟迟无法暴露,造成用户的投诉,那就得不偿失了。
由于个人技术有限,如果有理解不到位或者错误的地方,请留下评论,我会根据朋友们的建议进行修正
代码和注释都在里面,小伙伴们可以下载我上传的代码,亲测可运行~
Gitee 地址:https://gitee.com/vip-augus/spring-analysis-note.git
Github 地址:https://github.com/Vip-Augus/spring-analysis-note
参考资料
Spring Core Container 源码分析三:Spring Beans 初始化流程分析
Spring 源码深度解析 / 郝佳编著. -- 北京 : 人民邮电出版社