java 为什么会出现bin循环?

z2acfund  于 2023-03-28  发布在  Java
关注(0)|答案(3)|浏览(131)

我试图实现一个小服务器的商品商店,但我有一个错误,我做的一切根据教程,所以我不能理解的循环发生在任何方式。也许我的眼睛是模糊的,我看不到日志。我会很高兴的任何提示。为什么他输出的问题,而不是文字谢谢!

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }
    @Basic
    private AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
        auth.setUserDetailsService(userService);
        auth.setPasswordEncoder(passwordEncoder());
        return auth;
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/product/edit").hasAuthority(Role.ADMIN.name())
//                .antMatchers("/product/edit").hasAuthority(Role.ORGANIZACION.name())
//                .antMatchers("/order").hasRole(Role.CLIENT.name())
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/auth")
                .permitAll()
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/").deleteCookies("JSESSIONID")
                .invalidateHttpSession(true)
                .and()
                .csrf().disable();
    }

}
public interface UserService extends UserDetailsService {//security
    boolean save(UserDTO userDTO);
}
@Service
public class UserServiceImpl  implements UserService{
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public boolean save(UserDTO userDto) {
        if(!Objects.equals(userDto.getPassword(), userDto.getMatchingPassword())){
            throw new RuntimeException("Password is not equal");
        }
        User user = User.builder()
                .usernames(userDto.getUsername())
                .password(passwordEncoder.encode(userDto.getPassword()))
                .email(userDto.getEmail())
                .role(Role.CLIENT)
                .build();
        userRepository.save(user);
        return true;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findFirstByUsernames(username);
        if(user == null){
            throw new UsernameNotFoundException("User not found with name: " + username);
        }

        List<GrantedAuthority> roles = new ArrayList<>();
        roles.add(new SimpleGrantedAuthority(user.getRole().name()));

        return new org.springframework.security.core.userdetails.User(
                user.getUsernames(),
                user.getPassword(),
                roles);
    }
}

错误

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'securityConfiguration': Requested bean is currently in creation: Is there an unresolvable circular reference?

2023-03-27T01:07:18.156+03:00 ERROR 4484 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

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

Description:

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

???????
|  securityConfiguration
?     ?
|  userServiceImpl defined in file [C:\Users\amir1\IdeaProjects\bridge-web\project\TestTask\target\classes\com\example\testtask\service\UserServiceImpl.class]
???????

Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
nhaq1z21

nhaq1z211#

你有一个循环依赖,因为Spring不能确定它应该以什么顺序创建你的类。
要创建SecurityConfiguration,它需要自动连接一个UserServiceImpl。但是要创建一个UserServiceImpl,它需要在SecurityConfiguration中创建一个PasswordEncoder
所以你需要打破这种循环依赖。
因此,您要么需要从UserDetailsImpl中提取save函数,并将其放置在一个未自动连接到SecurityConfiguration的类中。
或者在单独的@Configuration注解类中提取并创建PasswordEncoder

gpfsuwkq

gpfsuwkq2#

PasswordEncoder bean移动到另一个配置中。
例如:

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

@Configuration
public class PasswordConfig {
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
6tqwzwtp

6tqwzwtp3#

用简单的英语,你告诉spring:

  • 要创建passwordEncoder,请使用SecurityConfig并调用其passwordEncoder()方法
  • 要创建SecurityConfig,请注入UserDetailsService
  • 要创建UserDetailsService,请注入passwordEncoder

这是一个鸡和蛋的问题:要创建passwordEncoder,我们需要SecurityConfig,它需要UserDetailsService,它需要passwordEncoder,这就是我们试图创建的!这个递归永远不会结束!
所以你需要切断这个循环,所以让我们检查一下我们是否真的需要这些依赖项:

  • passwordEncoder需要SecurityConfig吗?这听起来很合理。
  • UserDetailsService需要passwordEncoder吗?肯定需要。
  • SecurityConfig是否需要UserDetailsService?这似乎是不必要的。毕竟,SecurityConfig中的大多数方法都不需要UserDetailsService,特别是passwordEncoder()

您应该只在真正需要UserDetailsService的时候才请求它,也就是您要创建authenticationProvider的时候,而不是每次您想要创建任何在SecurityConfig中声明的bean的时候。
最简单的方法是注入一个Provider而不是一个完全初始化的bean,并且只在实际需要时向提供者请求初始化的示例:

@Configuration
public class SecurityConfig {
    @Inject 
    Provider<UserDetailsService> userDetailsService;

    @Bean
    AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
        auth.setUserDetailsService(userDetailsService.get());
        auth.setPasswordEncoder(passwordEncoder());
        return auth;
    }
}

或者,您可以在JavaConfig中声明UserService,而不是通过组件扫描,在这种情况下,工厂方法可以用于查找bean:

@Configuration
public class SecurityConfig {
    @Bean
    UserService userService() {
        return new UserServiceImpl();
    }

    @Bean
    AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
        auth.setUserDetailsService(userService());
        auth.setPasswordEncoder(passwordEncoder());
        return auth;
    }
}

相关问题