当前位置: 首页 > wzjs >正文

大香蕉网站人人做潍坊网站模板建站

大香蕉网站人人做,潍坊网站模板建站,网站建设关键词优化价格,北京有实力的软件开发公司目录 三级缓存核心原理 循环依赖的解决过程 1. Bean A创建过程中提前曝光工厂 2. Bean B创建时发现依赖A,从缓存获取 3. Bean A继续完成初始化 三级缓存的作用总结 二级缓存为何不够解决缓存依赖? 三级缓存如何解决? 为什么不直接在…

目录

三级缓存核心原理

循环依赖的解决过程

1. Bean A创建过程中提前曝光工厂

2. Bean B创建时发现依赖A,从缓存获取

3. Bean A继续完成初始化

三级缓存的作用总结

二级缓存为何不够解决缓存依赖?

三级缓存如何解决?

为什么不直接在实例化后创建代理?

总结


Spring通过三级缓存机制解决循环依赖问题,这与populateBean()方法密切相关。下面我用简化代码解释这个机制:

三级缓存核心原理

Spring在DefaultSingletonBeanRegistry中维护了三个重要的缓存:

// 一级缓存:存储完全初始化的单例bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存储早期曝光的单例bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三级缓存:存储单例工厂对象,用于创建早期曝光的bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环依赖的解决过程

当发生循环依赖时,Spring通过以下步骤解决:

1. Bean A创建过程中提前曝光工厂
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1. 实例化Bean(调用构造函数)BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);// 2. 提前曝光一个ObjectFactory,用于解决循环依赖boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences);if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 填充属性(可能触发对Bean B的依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化Bean(调用init方法和AOP代理)exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}// 将工厂添加到三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}
}
2. Bean B创建时发现依赖A,从缓存获取

populateBean()处理B的依赖时:

protected Object resolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {// 查找依赖的bean(假设这里是A)String dependencyName = descriptor.getDependencyName();// 从三级缓存中获取beanObject bean = getSingleton(dependencyName, false);return bean;
}// 从三级缓存中获取bean的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 先从一级缓存获取Object singletonObject = this.singletonObjects.get(beanName);// 2. 如果一级缓存没有且bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 3. 从二级缓存获取singletonObject = this.earlySingletonObjects.get(beanName);// 4. 二级缓存没有且允许早期引用if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 5. 从三级缓存获取工厂ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 6. 通过工厂创建早期bean实例singletonObject = singletonFactory.getObject();// 7. 放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 8. 从三级缓存移除this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
3. Bean A继续完成初始化

当B完成创建后,A继续完成自己的初始化:

// 完成Bean A的初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);// 将完全初始化的bean放入一级缓存
addSingleton(beanName, exposedObject);protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);}
}

三级缓存的作用总结

  1. 一级缓存(singletonObjects):存储完全初始化的单例bean,可直接使用
  2. 二级缓存(earlySingletonObjects):存储早期曝光的bean(未完成初始化),用于解决循环依赖
  3. 三级缓存(singletonFactories):存储工厂对象,允许在需要时创建早期bean,并支持AOP代理

通过这种机制,Spring允许在bean尚未完全初始化时就将其引用暴露给依赖它的其他bean,从而解决循环依赖问题。注意:只有单例作用域的bean支持循环依赖,原型模式不支持。你的问题非常关键!实际上,二级缓存理论上可以解决循环依赖,但Spring依然使用三级缓存,主要出于AOP代理的考虑。我来详细解释:

二级缓存为何不够解决缓存依赖?

假设只有两级缓存:

  1. singletonObjects(完全初始化的bean)
  2. earlySingletonObjects(早期曝光的bean)

当出现循环依赖时,我们可以在实例化后直接将bean放入earlySingletonObjects。但这样会有一个问题:如果bean需要AOP代理,早期曝光的将是原始对象,而不是代理对象

举个例子:

// Bean A依赖B,Bean B依赖A
class A {@Autowired private B b;@Transactional public void doSomething() {} // 需要AOP代理
}class B {@Autowired private A a;
}

当A和B循环依赖时:

  1. A实例化后放入二级缓存(此时是原始对象)
  2. B创建时从二级缓存获取A的原始对象
  3. B完成创建,注入A的原始对象
  4. A继续初始化,创建代理对象

最终结果:B持有的是A的原始对象,而不是代理对象,导致AOP失效!

三级缓存如何解决?

Spring通过三级缓存引入了ObjectFactory,将AOP代理的创建延迟到真正需要早期引用时:

// 三级缓存:存储工厂对象,用于创建可能需要代理的早期bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 添加工厂到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 获取早期引用的方法(可能创建代理)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会创建代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

当B需要A的早期引用时:

  1. 从三级缓存获取ObjectFactory
  2. 通过工厂调用getEarlyBeanReference(),此时才决定是否创建代理
  3. 将结果(可能是代理对象)放入二级缓存

这样一来,B持有的就是A的代理对象,保证了AOP的正确性。

为什么不直接在实例化后创建代理?

你可能会问:为什么不直接在实例化A后就创建代理,然后放入二级缓存?这样不就不需要三级缓存了吗?

原因有两点:

  1. 性能优化:不是所有bean都需要代理,延迟到真正需要时再创建可以避免不必要的代理
  2. 顺序正确性:Spring的后置处理器执行顺序是有规范的。postProcessBeforeInitializationpostProcessAfterInitialization应该在bean初始化阶段执行,而不是实例化阶段。如果提前创建代理,会破坏这个顺序。

总结

二级缓存可以解决普通对象的循环依赖,但无法解决代理对象的循环依赖。三级缓存通过引入ObjectFactory,将代理创建延迟到真正需要早期引用时,既保证了AOP的正确性,又维持了后置处理器的执行顺序。这是Spring在循环依赖和AOP之间找到的精妙平衡点。

http://www.dtcms.com/wzjs/28863.html

相关文章:

  • 提高网站关键词排名网站建设网络推广平台
  • 品牌推广部seo泛目录培训
  • unity3d做网站宽带营销案例100例
  • 网站开发企业培训报名百度销售系统
  • 广州市住房城乡建设局网站百度竞价推广效果怎么样
  • 网站 头尾调用公司网络推广排名定制
  • 泉州网站建设网络推广搜索app下载安装
  • 两学一做 官方网站网络营销过程步骤
  • 山东高端网站建设互联网品牌营销公司
  • 网站设置怎么清除百度竞价排名是哪种方式
  • 淄博企业网站建设公司郑州厉害的seo优化顾问
  • 做网站怎么制作手机优化助手
  • 做网站那家比较好百度seo刷排名工具
  • 要怎样夸一个网站做的好看东莞疫情最新通知
  • 上海公司招聘信息查询上首页的seo关键词优化
  • 外贸网站 在线留言软件推广怎么做
  • 静态网站规范今日军事新闻最新消息新闻
  • 浙江网站建设价格沧州网站seo公司
  • jsp 响应式网站模板下载长沙百度
  • 深圳做分销网站的公司浙江网站建设制作
  • 长春市大学生网站建设上海哪家seo公司好
  • 温州通告最新合肥seo排名扣费
  • 网站做政务长春seo招聘
  • 网站防御怎么做微信指数查询
  • 深圳注册公司流程及资料怎样在网上办理网站搜索引擎优化方法
  • 中国市政建设局网站谷歌aso优化
  • 世界500强企业名单2022seo国外推广软件
  • 网站建设功能宁德市自然资源局
  • 微网站促销版什么是软文营销?
  • 泸州中泸集团建设有限公司网站什么是搜索引擎竞价推广