前言
昨天的文章里提到Bean的加载流程和如何获取bean,今天继续源码解读。还是老规矩,看着Bean加载的时序图进入主题。 首先是Bean的创建,调用了ObjectFactory的getObject()方法,方法内部直接return了createBean()的方法。
@1.3.1.1 createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; //@1.3.1.1 锁定class 根据设置的class属性后者根据className来解析class,反射 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // TODO Prepare method overrides. 验证以及准备覆盖方法 try { //@1.3.1.2 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) {} try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. //@1.3.1.3 返回一个代理来替代真正的实例 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) {} try { //@1.3.1.4重点中的重点 创建Bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {} catch (Throwable ex) {} } 复制代码
大致梳理下这个方法的功能:
1. 根据RootBeanDefinition中的class属性或者beanName解释Class
2. 处理override的属性
3. 初始化前的后置处理器(也是AOP的核心实现)
4. 创建bean的具体逻辑
@1.3.1.2 处理override的属性 mbdToUse.prepareMethodOverrides()
ps: 这里注意哈,版本不一样的话,有一些方法是进行改造过的,所以有时候遇到错误或者难以解决的问题,可以想想是不是版本的问题,我个人因为版本问题也吃了不少的亏。
从上面代码我们可以看到,获取类的重载方法列表,然后遍历,一个一个进行处理。具体处理的是 lookup-method 和 replaced-method 属性,这个步骤解析的配置将会存入 beanDefinition 中的 methodOverrides 属性里,是为了待会实例化做准备。摘抄选自《Spring源码深度解析》
@1.3.1.3 实例化前的前置处理,注意两个重要点applyBeanPostProcessorsBeforeInstantiation(前置处理)和applyBeanPostProcessorsAfterInitialization(后置处理)
方法是为了在调用doCreateBean()之前的短路操作,如果后置处理成功,将直接返回Bean不在继续执行,这里是AOP的核心逻辑。说到AOP谁都知道,无非就是依赖注入而已,实现热插拔的比如日志,权限等等功能,但是实际上AOP能做的事情很多,后面时间充裕的话也解读一下AOP的源码。言归正传我们继续往下看源码。
@1.3.1.4 doCreateBean() bean的具体创建逻辑
在Spring的源码中,do开头的方法都是真正干活的(了解和使用servlet写代码的童鞋应该也是有这种体会),当然bean的创建也就是在doCreateBean()方法中完成的,下面是源码解析。大致流程梳理:
1.单例需要清除缓存
2.创建Bean的实例,并将BeanDefinition转换为包装类BeanWrapper
3.后处理器修改合并后的 bean 定义:bean 合并后的处理,Autowired 注解正式通过此方 法实现诸如类型的预解析
4.依赖处理
5.属性填充
6.循环依赖检查
7.注册DisposableBean(bean销毁时执行destroy())
8.完成创建并返回
因为这个方法做的事情太多了而且很复杂,这里只挑出重点去解析。
@1.3.1.4.1 创建Bean的实例,类createBeanInstance
大致流程梳理:
1. 判断是否有工厂方法,有的话则直接使用工厂方式创建bean
2. 没有工厂方法使用构造函数去创建,因为一个Class可能有多个构造函数,所以去需要根据 参数去区分具体的哪个构造方法。
3. 工厂和带参构造都不存在的话使用默认的构造函数。
继续下一步
@1.3.1.4.2 循环依赖的处理
Spring是通过在Bean实例化完成之前将ObjectFactory加入单例工厂singletonFactories的之中,@1.1 讲了ObjectFactory 是创建对象时使用的工厂。 在对象实例化时,会判断自己依赖的对象是否已经创建好了,判断的依据是查看依赖对象的 ObjectFactory 是否在单例缓存中,如果没有创建将会先创建依赖的对象,然后将 ObjectFactory 放入单例缓存。这时如果有循环依赖,需要提前对它进行暴露,让依赖方找到并正常实例化。
@1.3.1.4.2 属性的注入,方法populateBean(),这里不多赘述
大致流程梳理:
1.调用 InstantiationAwareBeanPostProcessor 处理器的 postProcessAfterInstantiation 方法,判断控制程序是否继续进行属性填充
2.根据注入类型(byName/byType),提取依赖的 bean,统一存入 PropertyValues 中,但是现在大部分是注解的形式,这俩个方法都不会执行
3. 判断是否需要进行 BeanPostProcessor 和 依赖检查,这一步是重点开始注入bean
4. 将所有解析到的 PropertyValues 中的属性填充至 BeanWrapper 中。
在这个方法中,根据不同的注入类型进行属性填充,然后调用后处理器进行处理,最终将属性应用到 bean 中。方法的内容实在太多,也不细说了,主要说下循环依赖的情况,在第2步根据属性注入的时候,假设A需要注入B,恰巧B也需要注入A,这时候无论是autowireByName/autowireByType还是postProcessPropertyValues最终都会调用getBean方法去创建Bean B。这时候通过 getSingleton()方法获取A在@1.3.1.4.2 放入缓存的ObjectFactory,并且通过getObject方法获取A的bean,这时候解决了循环依赖的问题。
@1.3.1.4.3 初始化bean
这个方法大致流程就是Bean分为俩种一种是FactoryBean,另一种就是普通的Bean,普通的bean会直接返回,FactoryBean会委托给getObjectFromFactoryBean进行获取。 Spring中有BeanFactory和FacotryBean要好好区分下:
1. BeanFactory接口的实现类是容器,也是IOC的基本规范。
2. FacotryBean接口的实现类具体返回什么Bean是有实现类的getObject()返回的决定。
总结: 以上两篇文章结合时序图和源码希望帮助大家对Spring加载Bean的过程有个更深的理解。同时不得不感叹Spring源码写的真好,对逻辑的拆解细分真的太强了,笔者每隔一段时间看一某一小模块的源码总会有一些新的理解,但是个人能力暂时有限,如果有什么理解不对的地方希望多加指正!感谢!下一个系列是好用的开源软件安利篇。