You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.0.6循环依赖问题解决(避免开启循环依赖允许配置)

为什么Spring不鼓励循环依赖,以及解决你的循环依赖问题

一、为什么不鼓励循环依赖

  • 耦合度过高:类之间互相绑定,修改其中一个类可能牵连多个关联类,维护成本急剧上升。
  • 初始化风险:Spring创建Bean时会陷入循环死锁,即便开启允许循环依赖,也可能出现Bean未完全初始化就被调用的情况,触发空指针或逻辑异常。
  • 设计缺陷信号:循环依赖大多意味着代码职责划分模糊,违反了单一职责、依赖倒置等设计原则,代码可读性和扩展性极差。

二、解决你的循环依赖问题

从你的依赖链和代码来看,循环的根源是:WebConfig → LoginCheckInterceptor → SessionLoginService → GeneralMemberService → PasswordEncoder(来自WebConfig的@Bean),形成闭环。

最优解决方案:拆分Bean配置

把PasswordEncoder的Bean从WebConfig中移到独立配置类,直接打破依赖链:

  1. 创建独立配置类(比如SecurityConfig):
@Configuration
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  1. 删除WebConfig中的passwordEncoder()方法,保留原有逻辑:
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

    private final LoginCheckInterceptor loginCheckInterceptor;
    private final LoginMemberArgumentResolver loginMemberArgumentResolver;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/members/register", "/members/sign-in", "/api/posts", "/api/posts/*");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(loginMemberArgumentResolver);
    }
}

这样GeneralMemberService依赖的PasswordEncoder不再与WebConfig绑定,循环依赖直接被打破,同时代码结构更清晰,符合单一职责原则。

可选临时方案:延迟加载(不推荐长期使用)

如果不想调整配置结构,可以给某个依赖添加@Lazy注解延迟Bean初始化,比如在WebConfig中注入拦截器时:

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

    private final @Lazy LoginCheckInterceptor loginCheckInterceptor;
    private final LoginMemberArgumentResolver loginMemberArgumentResolver;

    // 其他代码不变
}

但这种方法只是绕过问题,并未解决代码设计上的耦合,建议优先采用拆分配置的方案。

长远优化:精简依赖

观察你的LoginCheckInterceptor,它只用到了LoginService的getLoginMemberId()方法,而该方法仅从HttpSession取ID,完全不需要依赖MemberService。可以考虑拆分LoginService职责:

  • 抽离LoginSessionService接口,仅包含getLoginMemberId()、logout()等Session相关方法;
  • 让LoginCheckInterceptor依赖这个精简接口,而非完整的LoginService;
  • 原SessionLoginService同时实现这个精简接口和原LoginService。

这种方式能进一步降低依赖耦合,从根源上避免类似问题。

内容的提问来源于stack exchange,提问作者Jaeyeon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:22:29