Spring IOC 源码解析(三),Bean 实例的创建

Spring IOC 源码解析(三),Bean 实例的创建

第一步,prepareRefresh() ,方法刷新容器上下文信息,主要是设置它的开始时间、关闭状态、活跃状态。同时根据上下文环境初始化一些占位符的值,并且进行校验

第二步,obtainFreshBeanFactory() ,设置 BeanFactory 的 serializationId 后返回

第三步,prepareBeanFactory(beanFactory) ,做进一步的 BeanFactory 的准备工作,主要是为其增加 BeanClassLoader、BeanExpressionResolver、PropertyEditorRegistrar、BeanPostProcessor(BeanPostProcessor,ApplicationListenerDetector)等操作,之所以有这一步是因为后续的 Bean 的实例化以后 DI 的相关操作等会依赖这些类提供的操作;可以理解是为其设置了一系列的 静态代理 ,在 Bean 的实例化的过程中某些操作就需要通过这些代理去完成

2. 调用 BeanFactoryProcessor 和注册 BeanPostProcessor

BeanFactoryProcessor 涉及到的内容也比较多,会单独写一篇文章来介绍用法和分析源码,这里简单介绍一下

Spring IOC 源码解析(三),Bean 实例的创建

首先调用 postProcessBeanFactory(beanFactory); 这是一个留给子类实现的方法,此处没有做任何逻辑

然后调用 invokeBeanFactoryPostProcessors(beanFactory); 这里注释是调用已经注册在上下文中的 BeanFactoryPostProcessor;实际上就算没有注册过的,它也会从 BeanFactory 中的 BeanDefinitionNames 中获取对应的 BeanFactoryProcessor,然后调用 beanFactory.getBean 方法将其实例化。他主要做什么工作呢,我举个例子我们使用 Spring 的时候有时候是基于 JavaConfig 的,会在某个类上面配置 @ComponentScan("com.xx.xxx"),这种在最初加载 BeanDefinition 的时候不会去解析 @ComponentScan("com.xx.xxx"),会在这个方法中解析该注解并且扫描对应路径将其下的 BeanDefinition 转入 BeanFactory 中。

然后调用 registerBeanPostProcessors(beanFactory); 该方法会去 BeanFactory 中的 BeanDefinitions 中获取 BeanPostProcessor 的实现类的 BeanDefinition 然后调用 getBean 方法将其实例化,然后将他们进行排序后注册到 BeanFactory 的 beanPostProcessors 中。相当于就是提前一步将其实列化为对象,以便于为后续实列化对象这个过程服务。

BeanPostProcessor 有很多的实现的子类,它们分别穿插于实例化 Bean 逻辑的各个地方,可以极其灵活的调整实列化方式,和增加代理,修改 Bean 等功能;比如可以在 Bean 实例化前检查时候注册有 InstantiationAwareBeanPostProcessor 该实现可以提前返回代理对象,如果返回了,那么后续的实例化操作就不会在进行;比如 MergedBeanDefinitionPostProcessor 他可以在创建了早期 Bean 对象(后面会将上面是早期 Bean 对象)之后去合并 BeanDefinition 的内容,这次修改可以影响到后续给早期 Bean 注入属性值等内容等等

3. 实列化单例对象

Spring IOC 源码解析(三),Bean 实例的创建

实列化 Bean 的切入点主要逻辑就发生在这个方法中

3.1 获取已经实例的对象

Spring IOC 源码解析(三),Bean 实例的创建

第一步, getSingleton 可以从中获取已经注册到容器中的单例对象,或者早期单例对象;获取到单例对象我们很好理解,比如 A 依赖于 B,在对 A 进行依赖注入的时候,会递归的实列化 A 所依赖的对象比如 B,如果这里 B 已经被实例化过了那么直接返回就能附带完整 A 的依赖注入。那么早期对象是什么意思呢,比如对象 C 依赖对象 D,对象 D 又依赖对象 C,目前正在进行 C 的实例化操作 D 还未被实例化,此时首先根据反射创建出 C 实例,然后将其放入早期 Bean 实例的 Map 容器中,然后进行属性填充发现依赖 D,此时调用 getBean 对 D 进行实例化,依然将其放入早期 Bean 实例的 Map 容器中,又发现 D 又依赖 C,怎么办呢这个时候其实 C 是没有实例化和初始化完成的,其实就是从中取出之前放入早期 Bean 实例的 Map 中的 C 对象引用,然后返回,这样就能解决循环依赖问题

第二步, getObjectForBeanInstance 意思就是返回的 Bean 实例可能是个 FactoryBean 也可能是个普通 Bean 实例,那么就封装个方法普通 Bean 直接返回,FactoryBean 就调用其 getObject 方法来返回 Bean 实例(这里和本文都只是描述主要内容,还有一些其它逻辑自己看源码吧)

3.2 检查 BeanDefinition 是否存在于当前 BeanFactory

Spring IOC 源码解析(三),Bean 实例的创建

第一步,获取 ParentBeanFactory(可以通过 setParent 设置父 BeanFactory 实现)

第二步,如果在当前 BeanFactory 中没有找到该 BeanName 对应的 BeanDefinition 就递归的寻找父工厂,直到找到为止

3.3 创建早期 Bean 实例

Spring IOC 源码解析(三),Bean 实例的创建
Spring IOC 源码解析(三),Bean 实例的创建

第一步,调用 resolveBeanClass 从 BeanDefinition 中获取其 Class 属性

第二步,调用 resolveBeforeInstantiation 给 BeanPostProcessor 一个返回代理对象的机会,如果返回了的话,就不在走后续的实列化,初始化等流程了,这个方法的核心逻辑如下

Spring IOC 源码解析(三),Bean 实例的创建
Spring IOC 源码解析(三),Bean 实例的创建

比如我们自定义了一个实现类如下

Spring IOC 源码解析(三),Bean 实例的创建

此时对 c 这个类的实列化的后续流程将不在执行,此处直接返回该代理对象,然后会调用 applyBeanPostProcessorsAfterInitialization 直接初始化的后续逻辑

Spring IOC 源码解析(三),Bean 实例的创建

一般来说如果没有特殊设置这里是没有返回代理对象的,将会继续执行后续步骤

Spring IOC 源码解析(三),Bean 实例的创建
Spring IOC 源码解析(三),Bean 实例的创建

第一步,调用 createBeanInstance 创建 BeanWrapper,一个 Bean 的包装类,此处点击去看发现一般情况下就是走的反射创建,构造器.newInstance(args) 来创建该对象并且对其进行包装后返回

第二步,获取到 BeanWrapper 中的 早期 Bean 实例,之所以说是早期是因为它还是一个不完整的实列还未经历初始化和属性注入等相关操作

第三步,执行 MergedBeanDefinitionPostProcessor 的一些操作合并 BeanDefinition 的信息如果需要的话

Spring IOC 源码解析(三),Bean 实例的创建
Spring IOC 源码解析(三),Bean 实例的创建

这里调用 addSingletonFactory 就是解决循环依赖问题的第二个关键步骤,分别将其添加到 singletonFactories 和 registeredSingletons 中,我们在来配合这 doGetBean 中调用 getSingleton 方法来看

Spring IOC 源码解析(三),Bean 实例的创建

首先 singletonFactories 中获取到 ObjectFactory 然后调用其 getObject 方法后放入 earlySingletonObjects 中并且返回,在调用 getObject 的时候其实是调用的 getEarlyBeanReference(beanName, mbd, bean) 这个方法

Spring IOC 源码解析(三),Bean 实例的创建

能够看到这里又有 BeanPostProcessor 的操作,主要做的逻辑就是在返回 Bean 实例前又留给用户可以调整早期 Bean 实例的机会

到这一步早期的 Bean 实例就创建完成了,后面就是该填充 Bean 的属性和执行初始化方法了。目前可以看到 BeanPostProcessor 穿插在实例实例化的各个地方,极尽可能的给框架提供更加强大的拓展性,后面的逻辑还会再次接触到 BeanPostProcessor

总结

早期 Bean 的实列化的流程,首先进行 BeanFactory 的准备工作包括设置 ClassLoader 设置基础 BeanPostProcessor 初始化占位符对应的值设置 BeanFactory 的工作状态等待。然后调用 BeanFactoryPostProcessor 给容器一次再调整容器中的 BeanDefinitions 的机会(比如说将 @ComponentScan("com.xxx")路径下的注解类扫描装载为 BeanDefinition 到容器中和调用我们自定义的一些 BeanFactoryProcessor 等)。随后根据 BeanDefinition 取出 Class 然后通过反射进行实例化一个早期的 Bean 实例,当然在之前还有一个调用 BeanPostProcessor 存在一个返回代理对象的机会如果返回就不进行后续的逻辑。最后将早期 Bean 实例构建为 ObjectFactory 放入 singletonFactories 中结合 getSingleton 方法完美的解决了单例的循环依赖问题,由于是一个 ObjectFactory 在调用 getObject 的时候会调用 getEarlyBeanReference 方法其中会检测如果有 BeanPostProcessor(SmartInstantiationAwareBeanPostProcessor) 的话会调用该实现来覆盖当前的早期 Bean 对象

根据目前几章的源码分析能够看到,Spring 利用了各种设计模式和钩子方法和 BeanFactoryProcessor 和 BeanPostProcessor 使得其及其灵活,利用这些我们能够很容易的定制第三方框架功能。目前运用了代理模式、委派模式、魔板方法模式、策略模式、工厂模式等等,后面会单独写一篇文章来聊聊 Spring 中的这些设计模式

原文 

https://juejin.im/post/5f082662f265da22f751c8fe

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Spring IOC 源码解析(三),Bean 实例的创建

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址