Spring Boot 3.3.4循环依赖问题求助:UnsatisfiedDependencyException报错
解决Spring Boot 3.3.4中WebSecurityConfig的循环依赖问题
报错原因
你遇到的UnsatisfiedDependencyException是因为WebSecurityConfig通过构造器注入了PasswordEncoder,而PasswordEncoder的@Bean方法又定义在同一个类中。Spring容器在创建WebSecurityConfig实例时,需要先获取PasswordEncoder Bean,但PasswordEncoder的Bean创建依赖WebSecurityConfig类的实例(Bean方法属于该类),从而形成无法解析的循环依赖。
解决方案
方案1:移除构造器注入,直接调用本地@Bean方法
由于passwordEncoder()是被@Bean标记的方法,Spring会保证每次调用都返回容器中的单例Bean实例,因此可以直接在需要的地方调用该方法,无需注入:
package elements.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration @EnableWebSecurity public class WebSecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .logoutSuccessUrl("/login"); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } // 移除@Autowired,直接调用passwordEncoder()方法 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user1ka").password(passwordEncoder().encode("y445uri125")).roles("USER") .and() .withUser("user2ka").password(passwordEncoder().encode("sa678sha769")).roles("USER"); } }
方案2:使用@Lazy延迟加载PasswordEncoder
如果需要保留构造器注入,可以通过@Lazy注解延迟PasswordEncoder的初始化,打破循环依赖链:
// 修改构造器注入部分 @Autowired public WebSecurityConfig(@Lazy PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; }
额外建议
NoOpPasswordEncoder已被标记为过时,生产环境中强烈建议使用安全的密码编码器,比如BCryptPasswordEncoder:
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
内容的提问来源于stack exchange,提问作者Ganiel24
相关产品推荐
相关产品推荐

