网站seo方案建设目标,网站安全优化,山西省建设工程信息网,填写网站信息一、Spring在创建Bean的过程中分三步
实例化#xff0c;对应方法#xff1a;AbstractAutowireCapableBeanFactory中的createBeanInstance方法#xff0c;简单理解就是new了一个对象。属性注入#xff0c;对应方法#xff1a;AbstractAutowireCapableBeanFactory的populat…一、Spring在创建Bean的过程中分三步
实例化对应方法AbstractAutowireCapableBeanFactory中的createBeanInstance方法简单理解就是new了一个对象。属性注入对应方法AbstractAutowireCapableBeanFactory的populateBean方法为实例化中new出来的对象填充属性和注入依赖。初始化对应方法AbstractAutowireCapableBeanFactory的initializeBean执行aware接口中的方法初始化方法完成AOP代理。
二、三级缓存
private final MapString, Object singletonObjects new ConcurrentHashMap(256);
private final MapString, Object earlySingletonObjects new HashMap(16);
private final MapString, ObjectFactory? singletonFactories new HashMap(16);
singletonObjects第一级缓存存放可用的完全初始化成品的单例Bean。
earlySingletonObjects第二级缓存存放半成品的Bean半成品的Bean是已创建对象但是未注入属性和初始化。用以解决循环依赖。
singletonFactories第三级缓存存的是Bean工厂对象用来生成半成品的Bean并放入到二级缓存中。用以解决循环依赖。如果Bean存在AOP的话返回的是AOP的代理对象。
三级缓存的 key 是 beanNamevalue 是一个 lambda 表达式这个 lambda 表达式的作用就是进行提前 AOP。
三、三个 map 的配合过程
1、首先获取单例 Bean 的时候会通过 BeanName 先去 singletonObjects一级缓存 查找完整的 Bean如果找到则直接返回否则进行步骤 2。
2、看对应的 Bean 是否在创建中如果不在直接返回找不到如果是则会去 earlySingletonObjects 二级缓存查找 Bean如果找到则返回否则进行步骤 3。
3、去 singletonFactories 三级缓存通过 BeanName 查找到对应的工厂如果存着工厂则通过工厂创建 Bean 并且放置到 earlySingletonObjects 中。
4、如果三个缓存都没找到则返回 null。 为了解决二级缓存中 AOP 生成新对象的问题Spring 中的解决方案就是提前 AOP。
四、Spring 为什么不用二级缓存来解决循环依赖问题
Spring 原本的设计是bean 的创建过程分三个阶段 1 创建实例 createBeanInstance – 创建出 bean 的原始对象 2 填充依赖 populateBean – 利用反射使用 BeanWrapper 来设置属性值 3 initializeBean – 执行 bean 创建后的处理包括 AOP 对象的产生 在没有循环依赖的场景下第 1,2 步都是 bean 的原始对象第 3 步 initializeBean 时才会生成 AOP 代理对象。
循环依赖属于一个特殊的场景如果在第 3 步 initializeBean 时才去生成 AOP 代理 bean 的话那么在第 2 步 populateBean 注入循环依赖 bean 时就拿不到 AOP 代理 bean 进行注入。 所以循环依赖打破了 AOP 代理 bean 生成的时机需要在 populateBean 之前就生成 AOP 代理 bean。 而且生成 AOP 代理需要执行 BeanPostProcessor而 Spring 原本的设计是在第 3 步 initializeBean 时才去调用 BeanPostProcessor 的。 并不是每个 bean 都需要进行这样的处理所以 Spring 没有直接在 createBeanInstance 之后直接生成 bean 的早期引用而是将 bean 的原始对象包装成了一个 ObjectFactory 放到了三级缓存singletonFactories。 当需要用到 bean 的早期引用的时候才通过三级缓存singletonFactories 来进行获取。
如果只使用二级缓存来解决循环依赖的话那么每个 bean 的创建流程中都需要插入一个流程——创建 bean 的早期引用放入二级缓存。
实际中绝大部分的情况下都不涉及到循环依赖而且 createBeanInstance -- populateBean -- initializeBean 这个流程也更加符合常理。
所以猜想Spring 不用二级缓存来解决循环依赖问题是为了保证处理时清晰明了bean 的创建就是三个阶段: createBeanInstance -- populateBean -- initializeBean 只有碰到 AOP 代理 bean 被循环依赖时的场景才去特殊处理提前生成 AOP 代理 bean。
理论上来说使用二级缓存是可以解决 AOP 代理 bean 的循环依赖的。只是 Spring 没有选择这样去实现Spring 选择了三级缓存来实现让 bean 的创建流程更加符合常理更加清晰明了。
五、多例不能循环依赖
多例的情况下每次getBean都会创建一个新的对象那么应该引用哪一个对象呢这本身就矛盾。多实例Bean是每次创建都会调用doGetBean方法根本没有使用一二三级缓存不能解决循环依赖。因而spring中对于多例之间相互引用是会提示错误的。