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

Spring Boot应用启动失败:WebSecurityConfig Bean存在循环依赖

解决Spring Boot WebSecurityConfig循环依赖问题

问题根源

你的WebSecurityConfig类存在循环依赖:

  • 类通过@AllArgsConstructor构造注入了BCryptPasswordEncoder实例
  • 但同时在同一个类中定义了BCryptPasswordEncoder的@Bean方法

这导致Spring容器陷入死循环:要创建WebSecurityConfig,必须先拿到BCryptPasswordEncoder实例;而创建BCryptPasswordEncoder实例,又需要先实例化WebSecurityConfig来调用其passwordEncoder()方法。

解决方案

方案1:移除构造注入,直接调用本地Bean方法

修改WebSecurityConfig,去掉构造注入的BCryptPasswordEncoder,在需要的地方直接调用passwordEncoder()方法:

package com.example.demo.security;

import com.example.demo.appuser.AppUserService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.DefaultSecurityFilterChain;

@Configuration
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig {

    private final AppUserService appUserService;

    @Bean
    public DefaultSecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .anyRequest().authenticated()
                );

        http.authenticationProvider(daoAuthenticationProvider());
        return http.build();
    }


    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        provider.setUserDetailsService(appUserService);
        return provider;
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

方案2:将密码编码器Bean移到独立配置类

创建单独的配置类来定义BCryptPasswordEncoder,避免和WebSecurityConfig互相依赖:

  1. 新建PasswordConfig类:
package com.example.demo.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class PasswordConfig {
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  1. 保留WebSecurityConfig的构造注入:
package com.example.demo.security;

import com.example.demo.appuser.AppUserService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.DefaultSecurityFilterChain;

@Configuration
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig {

    private final AppUserService appUserService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Bean
    public DefaultSecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .anyRequest().authenticated()
                );

        http.authenticationProvider(daoAuthenticationProvider());
        return http.build();
    }


    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        provider.setUserDetailsService(appUserService);
        return provider;
    }

}

说明

之前尝试的方法未生效的可能原因:

  • @Lazy注解未添加到正确的依赖项上,没有打破循环链
  • 拆分Bean时未彻底分离BCryptPasswordEncoder的定义,仍存在隐含依赖
  • spring.main.allow-circular-references=true配置未正确加载(比如配置文件路径错误、Spring版本兼容问题),但不建议依赖此配置,从根源消除循环依赖才是规范做法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:27:32