升级Spring Boot 2.7.18后如何解决A→B→C→A循环依赖问题?
先修正接口解耦的错误
你之前让SessionCreateInterceptor实现SessionManager属于职责错位——它的核心功能是请求拦截,而非会话池管理,这直接导致Spring容器中出现两个SessionManager实现类(SessionPool和SessionCreateInterceptor),引发多Bean冲突。
修正步骤:
- 仅保留
SessionPool实现SessionManager接口 SessionCreateInterceptor改为依赖SessionManager,而非实现它
修正后的SessionCreateInterceptor注入示例:
@Component @Scope("prototype") public class SessionCreateInterceptor extends AbstractSessionInterceptor { private final SessionManager sessionManager; // 构造器注入SessionManager public SessionCreateInterceptor(SessionManager sessionManager) { this.sessionManager = sessionManager; } // 原业务逻辑中用到SessionPool的地方,改为调用sessionManager的方法 }
拆解A→B→C→A的循环依赖
针对SessionPool→SessionCreateWrapper→SessionCreateInterceptor→SessionPool的循环链,可通过以下方式打破:
方案1:使用@Lazy延迟注入
在循环依赖的任意一端添加@Lazy注解,让Spring延迟初始化依赖Bean,规避启动时的循环检测:
比如在SessionCreateWrapper的构造器注入中添加@Lazy:
@Controller @Scope("prototype") public class SessionCreateWrapper extends WebServiceGatewaySupport { private final SessionManager sessionManager; public SessionCreateWrapper(@Lazy SessionManager sessionManager) { this.sessionManager = sessionManager; } }
或者在SessionPool依赖SessionCreateWrapper的地方添加@Lazy:
@Service public class SessionPool implements SessionManager { private final SessionCreateWrapper sessionCreateWrapper; public SessionPool(@Lazy SessionCreateWrapper sessionCreateWrapper) { this.sessionCreateWrapper = sessionCreateWrapper; } }
方案2:重构职责边界
循环依赖往往是职责不清晰的信号,可拆分核心逻辑打破循环:
- 让
SessionPool只负责会话的存储、获取(单一职责),移除它对SessionCreateWrapper的直接依赖 - 新增会话创建服务类(比如
SessionCreator),专门处理会话创建逻辑,由它依赖SessionCreateWrapper和SessionManager SessionCreateInterceptor需要创建会话时,调用SessionCreator而非直接依赖SessionPool
示例结构:
// 新增会话创建服务 @Service public class SessionCreator { private final SessionCreateWrapper sessionCreateWrapper; private final SessionManager sessionManager; public SessionCreator(SessionCreateWrapper sessionCreateWrapper, SessionManager sessionManager) { this.sessionCreateWrapper = sessionCreateWrapper; this.sessionManager = sessionManager; } public Security createAndStoreSession(SharedContext context) { Security session = sessionCreateWrapper.createSession(); sessionManager.addToPool(session); return session; } }
原循环链会被打破:SessionPool不再依赖SessionCreateWrapper,SessionCreateInterceptor依赖SessionCreator,SessionCreator依赖SessionCreateWrapper和SessionManager。
方案3:使用Provider延迟获取Bean
如果不想大幅修改代码,可通过org.springframework.beans.factory.ObjectProvider延迟获取依赖Bean,避免循环:
比如在SessionPool中使用ObjectProvider:
@Service public class SessionPool implements SessionManager { private final ObjectProvider<SessionCreateWrapper> sessionCreateWrapperProvider; public SessionPool(ObjectProvider<SessionCreateWrapper> sessionCreateWrapperProvider) { this.sessionCreateWrapperProvider = sessionCreateWrapperProvider; } // 需要使用SessionCreateWrapper时再获取实例 public void someMethod() { SessionCreateWrapper wrapper = sessionCreateWrapperProvider.getObject(); // 业务逻辑 } }
关于setter注入的补充
你之前尝试setter注入仍报错,大概率是循环链中还有其他Bean(比如WorkflowTrigger)参与了循环,需要确保所有循环依赖的节点都使用setter注入,或结合@Lazy一起使用。
内容的提问来源于stack exchange,提问作者Solv_it_kas

