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

手机做网站服务器网页设计与制作代码成品

手机做网站服务器,网页设计与制作代码成品,五大跨境电商平台对比分析,进入公众号后怎么编辑信息Spring 循环依赖详解 一、循环依赖 1. 什么是循环依赖 循环依赖是指两个或多个Spring Bean之间形成相互依赖的闭环关系。具体表现为: Bean A 依赖 Bean B Bean B 依赖 Bean C … Bean N 又依赖 Bean A 2. 循环依赖出现的场景 循环依赖通常出现在以下场景中&#xff…

Spring 循环依赖详解

一、循环依赖

1. 什么是循环依赖

循环依赖是指两个或多个Spring Bean之间形成相互依赖的闭环关系。具体表现为:
Bean A 依赖 Bean B
Bean B 依赖 Bean C

Bean N 又依赖 Bean A

2. 循环依赖出现的场景

循环依赖通常出现在以下场景中:

  • Bean初始化阶段
  • 当Spring容器启动,初始化Bean时
  • 特别是使用构造器注入方式时最容易暴露
  • 依赖注入时
  • 通过@Autowired进行字段/方法注入时
  • 使用XML配置中的或时
  • 特定设计模式中
  • 双向关联的业务场景(如订单-支付系统)
  • 相互回调的组件设计

3. 循环依赖会带来什么问题

  • 启动时抛出BeanCurrentlyInCreationException
  • 错误信息:“Requested bean is currently in creation: Is there an unresolvable circular reference?”
  • 每次获取bean都会尝试创建新实例
  • 最终导致栈溢出(StackOverflowError)

二、循环依赖的几种类型

1. Setter/Field注入循环依赖

@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}@Component
public class ServiceB {@Autowiredprivate ServiceA serviceA;
}

2. 构造器循环依赖

@Component
public class ServiceA {private final ServiceB serviceB;public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; }
}@Component
public class ServiceB {private final ServiceA serviceA;public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; }
}

三、Spring解决循环依赖的机制

1. 三级缓存机制(可解决注入循环依赖)

1.1 三级缓存

在初始化阶段(实例化之后),Spring使用三级缓存来解决单例Bean的循环依赖问题:

缓存级别名称存储内容作用
一级缓存singletonObjects完全初始化好的Bean提供最终可用的Bean
二级缓存earlySingletonObjects提前曝光的半成品Bean解决循环依赖
三级缓存singletonFactories对象工厂(ObjectFactory)生成代理对象

这是Spring三级缓存的部分源码

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {/** Cache of singleton objects: bean name to bean instance. *///  一级缓存private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. *///  三级缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. *///  二级缓存private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);...
}
1.2 解决流程(以A→B→A为例)
  1. 开始创建A,实例化A(调用构造器)
  2. 将A的对象工厂放入三级缓存
  3. 填充A的属性,发现需要B
  4. 开始创建B,实例化B(调用构造器)
  5. 将B的对象工厂放入三级缓存
  6. 填充B的属性,发现需要A
  7. 从三级缓存获取A的对象工厂,生成早期引用
  8. 将A的早期引用放入二级缓存,删除三级缓存中的A
  9. B完成属性注入,初始化完成
  10. A得到B的引用,继续完成初始化
  11. A初始化完成,放入一级缓存
  12. B中的A引用最终指向完全初始化的A

在这里插入图片描述

1.3 关键源码分析

DefaultSingletonBeanRegistry类中的关键方法:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查询Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存查询singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存获取ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

2. 懒加载(可解决构造循环依赖)

在实例化阶段,可使用@Lazy注解通过以下方式解决构造器循环依赖:
不立即初始化依赖的Bean
创建一个代理对象作为占位符
当实际需要调用依赖Bean时才进行初始化

@Service
public class ServiceA {private final ServiceB serviceB;public ServiceA(@Lazy ServiceB serviceB) {this.serviceB = serviceB;}
}@Service
public class ServiceB {private final ServiceA serviceA;public ServiceB(@Lazy ServiceA serviceA) {this.serviceA = serviceA;}
}

四、如何避免/解决循环依赖

1. 设计层面解决方案

  1. 重构代码:解耦相互依赖的组件
  2. 接口抽象:依赖接口而非具体实现
  3. 应用事件:使用事件机制代替直接调用
  4. 模板方法模式:将公共逻辑提取到父类

2. 技术层面解决方案

  1. 使用@Lazy延迟加载
@Component
public class ServiceA {@Lazy@Autowiredprivate ServiceB serviceB;
}
  1. 使用Setter注入代替构造器注入
@Component
public class ServiceA {private ServiceB serviceB;@Autowiredpublic void setServiceB(ServiceB serviceB) { this.serviceB = serviceB; }
}
  1. 使用@DependsOn指定初始化顺序
@Component
@DependsOn("serviceB")
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}
  1. 使用ApplicationContextAware手动获取Bean
@Component
public class ServiceA implements ApplicationContextAware {private ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext context) {this.context = context;}public void doSomething() {ServiceB serviceB = context.getBean(ServiceB.class);// 使用serviceB}
}

五、特殊场景处理

1. AOP代理下的循环依赖

Spring通过SmartInstantiationAwareBeanPostProcessor处理代理对象的循环依赖,关键类是AbstractAutoProxyCreator

2. 构造器注入的替代方案

如果必须使用构造器注入,可以考虑:

@Configuration
public class MyConfig {@Beanpublic ServiceA serviceA(@Lazy ServiceB serviceB) {return new ServiceA(serviceB);}
}

六、最佳实践建议

  1. 尽量避免循环依赖,这是代码设计问题而非技术问题
  2. 优先使用构造器注入(Spring官方推荐)
  3. 对于不可避免的循环依赖,使用Setter/Field注入
  4. 在大型项目中,使用模块化设计减少循环依赖
  5. 定期使用架构分析工具检测循环依赖
http://www.cotm.com.cn/news/331.html

相关文章:

  • 建设体育课程基地网站关键词排名点击软件
  • 怎样做邪恶网站汕头seo服务
  • 做影视网站该怎么发展中国网站排名查询
  • 创新的做pc端网站湖南关键词优化推荐
  • wordpress返回上一页插件长春seo优化企业网络跃升
  • 肃州区建设局网站网络安全培训最强的机构
  • 郑州专业网站制作的公司哪家好营销网络推广哪家好
  • 手机网站教程seo与sem的关系
  • 制作公司网站源代码怎么弄如何进行推广
  • wordpress wpposts湖南网站建设seo
  • 枣庄做网站建设的公司营销技巧五步推销法
  • 专业做化妆品外包材的招聘网站seo推广培训
  • 自己怎么做网站的聚合页面阿里巴巴官网首页
  • 上海 专业网站建设衡阳百度seo
  • 企业网站建设哪家公司好搜索引擎优化的基础是什么
  • 用asp.net做的网站实例拓客软件
  • 成都专做婚介网站的公司2023年5月最新疫情
  • wordpress 你好多莉黑帽seo是什么意思
  • 动感网站模板上海百网优seo优化公司
  • 科技公司的网站建设费入什么科目网络营销专业培训学校
  • 网站意义免费网站注册com
  • 常用网站缩略图自定义成都seo优化排名推广
  • 入门网站建设六年级上册数学优化设计答案
  • 网站建设设计细节seo关键词排名优化要多少钱
  • 网站开发建设明细报价表杭州千锋教育地址
  • 天津低价做网站百度推广怎么赚钱
  • 快速做网站的软件游戏推广员拉人犯法吗
  • 建设公司网站的意义创建一个网站需要什么
  • 简单的网页设计网站竞价网络推广托管
  • 网站纯色背景图怎么做站长工具seo优化