spring中三种依赖注入方式为:1.属性注入(字段注入),使用@autowired等注解直接注入,最常用但不推荐;2.设值注入(setter注入),通过setter方法注入,灵活性高但可能部分初始化;3.构造方法注入,通过构造函数注入,推荐用于强制依赖且不可变场景。

循环依赖中,属性注入(字段或 setter 注入)本身在单例 + 非代理场景下,Spring 三级缓存能自动解决,一般无需干预。但若你明确想“改用容器工厂”来主动管理依赖、绕过默认注入机制,核心思路是:**不靠 @Autowired 自动装配,而是通过 Spring 容器的工厂能力(如 ObjectFactory 或 ObjectProvider)延迟获取 Bean,把依赖解析时机从初始化阶段推迟到实际使用时**。
为什么用容器工厂能破环?
它不强制在 Bean 创建或属性填充阶段就拿到完整实例,而是提供一个“取对象”的能力。A 创建时不需要 B 的实例,只需要一个能 later 拿到 B 的“句柄”,B 同理。环在定义阶段就断开了。
常用容器工厂方式及写法
-
ObjectProvider
:推荐首选,轻量、语义清晰、支持懒查、可判空
示例:@Service<br>public class ServiceA {<br> private final ObjectProvider<serviceb> serviceBProvider;<br><br> @Autowired<br> public ServiceA(ObjectProvider<serviceb> serviceBProvider) {<br> this.serviceBProvider = serviceBProvider;<br> }<br><br> public void doWork() {<br> ServiceB b = serviceBProvider.getObject(); // 真正用时才取<br> b.handle();<br> }<br>}</serviceb></serviceb> -
ApplicationContext.getBean():直接手动取,灵活性高但耦合容器
需实现 ApplicationContextAware 接口,或注入 ApplicationContext(不推荐在业务类中强依赖上下文) -
ObjectFactory
:底层接口,ObjectProvider 就是它的封装升级版;一般直接用 ObjectProvider 更安全
和 @Lazy 的关键区别
@Lazy 是让 Spring 为你生成一个代理对象(比如 CGLIB 代理),首次调用方法时才真正初始化目标 Bean;而 ObjectProvider 是纯逻辑延迟,不引入代理,也不改变 Bean 类型,更适合需要保持原始类型、避免 AOP 干扰或单元测试隔离的场景。
适用边界注意
这种方式适合非构造器注入、且你希望显式控制依赖时机的场景。它不能替代设计优化——如果 A 和 B 确实职责混杂、互相强耦合,长期仍建议拆分接口或引入中介服务。容器工厂是务实解法,不是设计缺陷的遮羞布。











