Spring 源码系列: 依赖注入 (一)getBean
Spring 源码系列: 依赖注入 (二)createBean
Spring 源码系列: 依赖注入 (三)- 属性注入
在上面三篇文章中对依赖注入做了一个大致的梳理; 里面都是大量代码的分析, 本文在此基础上进行一个总结归纳
依赖注入调用过程
如前几篇文章所述, 依赖注入是由 getBean 来触发的; 然后涉及到 bean 实例的创建依赖关系的建立属性注入等子过程
getBean 方法触发依赖注入
doGetBean 从容器中查找 Bean(BeanFactory 链, 当前容器 -> 双亲容器 - 双亲容器...)
当然, 在获取到某个 Bean 的时候也会通过递归的方式来依赖注入依赖的 bean
createBeanInstance 生成了 Bean 所包含的 Java 对象, Spring 中用 SimpleInstantiationStrategy 类来生成 Bean 对象的实例, 实例化 Java 对象的方法有两种 (CGlib 是默认方式):
通过 BeanUtils, 它使用了 JVM 的反射功能来生成 Java 对象实例
用 CGLIB 来生成, CGLIB 是一种常用的字节码生成器的类库
populateBean 设置 Bean 对象的依赖关系
resolveValueIfNecessary 注入类型的处理; 解析不同类型的属性
setPropertyValues 属性注入
关于 lazy-init
Ioc 容器的初始化过程中, 主要的工作就是对 BeanDefinition 的定位载入解析和注册; 但是就像之前说过的, 此时依赖注入还没有发生在 Spring 源码系列: 依赖注入 (一)getBean 文中提到, 依赖注入发生在应用第一次向容器获取 Bean 的时候; 也就是上面说到的通过 getBean 来触发
当然, 依赖注入也可以在容器初始化的过程中就完成这个就是 lazy-init 属性的存在意义了就是说我们可以通过设置 Bean 的 lazy-init 属性来控制预实例化的过程
预实例化: 在初始化容器时完成 Bean 的依赖注入
这种做法的好处在于提高了我们第一次获取 Bean 的的效率, 但是它也降低了容器初始化的速度 (这个其实很好理解的, 因为第一次获取 Bean 的时候, 依赖注入已经完成了, 直接拿过来用就行)
关于 lazy-init 属性的处理也是在 wac.refresh 这个方法中完成的, 具体是在 finishBeanFactoryInitialization 方法中如果继续追溯的话, 最终是交给 DefaultListableBeanFactory 容器中的 preInstantiateSingletons 方法中完成
lazy-init 这种实例化方式就是通过将依赖注入委托给容器来处理, 而不是在用户第一向容器申请的 Bean 的时候完成依赖注入, 不同的阶段, 也有不同的优劣
来源: https://juejin.im/post/5a7a9e9a5188257a705101f9