Spring Security Bean循环依赖错误求助:BeanCurrentlyInCreationException排查
Spring Boot Security 循环依赖问题排查与解决
问题描述
启动Spring Boot应用时触发循环依赖错误,核心日志如下:
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2024-07-18T18:36:31.217+05:30 ERROR 16888 --- [ main] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'springSecurity': Requested bean is currently in creation: Is there an unresolvable circular reference? at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:355) ~[spring-beans-6.1.8.jar:6.1.8] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:227) ~[spring-beans-6.1.8.jar:6.1.8]
相关代码
Spring Security配置类
@Configuration @EnableWebSecurity public class SpringSecurity { @Autowired private UserDetailsServiceImpl userDetailsService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(request -> request .requestMatchers("/public/**").permitAll() .requestMatchers("/journal/**", "/user/**").authenticated() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated()) .httpBasic(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .build(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
POM.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.6</version> <relativePath/> </parent> <groupId>net.engineeringdigest</groupId> <artifactId>journalApp</artifactId> <version>0.0.1-SNAPSHOT</version> <name>JournalApp</name> <description>Application for Journals</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <version>3.1.4</version> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
问题原因与解决方法
核心原因
- 配置类命名为
SpringSecurity,Spring默认将其bean名称设为springSecurity,与框架内部组件名称冲突,初始化时触发循环引用。 configureGlobal(AuthenticationManagerBuilder)是Spring Security 5.x及更早版本的过时写法,在6.x版本中直接调用passwordEncoder()会绕开Spring容器管理,导致依赖初始化顺序混乱。
修复方案
修改配置类,采用Spring Security 6.x推荐的配置方式,同时规避命名冲突:
修改后的配置类
@Configuration @EnableWebSecurity public class SpringSecurityConfig { private final UserDetailsServiceImpl userDetailsService; private final PasswordEncoder passwordEncoder; // 构造函数注入,符合Spring最佳实践,避免循环依赖 public SpringSecurityConfig(UserDetailsServiceImpl userDetailsService, PasswordEncoder passwordEncoder) { this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(request -> request .requestMatchers("/public/**").permitAll() .requestMatchers("/journal/**", "/user/**").authenticated() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated()) .httpBasic(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) // 直接绑定认证相关Bean .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder) .build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
关键修改点
- 重命名配置类为
SpringSecurityConfig,避免与框架内部bean名称冲突。 - 使用构造函数注入替代字段注入,明确依赖初始化顺序,消除循环依赖风险。
- 移除过时的
configureGlobal方法,直接在SecurityFilterChain中绑定UserDetailsService和PasswordEncoder。 - 确保
UserDetailsServiceImpl类添加@Service注解,让Spring能自动扫描并创建其bean实例。
内容的提问来源于stack exchange,提问作者Jinendra
相关产品推荐
相关产品推荐

