【问题标题】:Why does the configuration class form a cyclical dependency with itself?为什么配置类会与自身形成循环依赖?
【发布时间】:2021-07-30 19:58:41
【问题描述】:

我不明白这个类是怎么产生循环依赖注入的。 我尝试添加 @Lazy 注释或从构造函数中删除 @Autowired ,但它没有帮助。可能房间里有一头我没看到的大象。

这是控制台显示的内容:

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  securityConfiguration defined in file [E:\Users\Adelin\eclipse-workspace2\AuthenticationSpringJWTAngular\target\classes\src\main\configuration\SecurityConfiguration.class]

这是配置类:

package src.main.configuration;

import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
import static src.main.constant.SecurityConstant.PUBLIC_URLS;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import src.main.filter.JWTAccessDeniedHandler;
import src.main.filter.JWTAuthenticationEntryPoint;
import src.main.filter.JWTAuthorizationFilter;
import src.main.service.IUserDetailsService;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private JWTAuthorizationFilter jwtAuthorizationFilter;
    private JWTAccessDeniedHandler jwtAccessDeniedHandler;
    private JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    private IUserDetailsService userDetailsService;
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public SecurityConfiguration(JWTAuthorizationFilter jwtAuthorizationFilter,
            JWTAccessDeniedHandler jwtAccessDeniedHandler, JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint,
            IUserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.jwtAuthorizationFilter = jwtAuthorizationFilter;
        this.jwtAccessDeniedHandler = jwtAccessDeniedHandler;
        this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder amb) throws Exception {
        amb.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//
                .cors().and() //
                // we're not using sessions, not keeping track of currently logging in users
                // users prove by using a token -> stateless
                .sessionManagement().sessionCreationPolicy(STATELESS).and() //
                .authorizeRequests().antMatchers(PUBLIC_URLS).permitAll() // no authentication
                                                                            // needed
                .anyRequest().authenticated().and() // anything else - reqs. authentication
                .exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler)
                .authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
                .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

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

【问题讨论】:

  • 为什么需要在配置类中接收BCryptPasswordEncoder 作为字段?你可以只做amb.userDetailsService(userDetailsService).passwordEncoder(this.bCryptPasswordEncoder());(调用方法bCryptPasswordEncoder()而不是传递字段)-当然,从类中删除字段bCryptPasswordEncoder

标签: spring spring-boot configuration javabeans


【解决方案1】:

我怀疑是因为这个

SecurityConfiguration 的构造函数被标记为@Autowired,其参数类型为BCryptPasswordEncoder,因此基本上为了实例化SecurityConfiguration,它需要一个BCryptPasswordEncoder 类型的bean。

但话又说回来,同一个类有一个实例方法,它正在创建 BCryptPasswordEncoder 类型的 bean。

所以基本上,构造函数不能被调用,因为它依赖于方法返回的值,而方法不能被调用,因为构造函数还没有被调用来实例化它。

如果您将方法更改为以下(我并不是建议将其作为解决方案,而只是为了验证我的理解),那么它可能会起作用。

@Bean
public static BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    • 2013-10-28
    • 2018-07-17
    • 2022-11-10
    相关资源
    最近更新 更多