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互相依赖:
- 新建
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(); } }
- 保留
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
相关产品推荐
相关产品推荐

