【问题标题】:Spring Boot. A Bean Depends on a Service弹簧靴。一个 Bean 依赖于一个服务
【发布时间】:2015-11-20 04:03:21
【问题描述】:

下面我有一个customUserDetailsService 属性和一个tokenAuthenticationService 属性。我需要将customUserDetailsService 传递给tokenAuthenticationService,但tokenAuthenticationService 是一个@Bean 文件,customUserDetailsService 是一个@Service,这意味着tokenAuthenticationService 首先被调用,UserDetailsService 的参数为null UserDetailsService 参数。我需要延迟 tokenAuthenticationService 作为 Bean 的启动或将 tokenAuthenticationService 转换为服务以及如何将这些参数作为构造函数传递。我该怎么做呢?

  package app.config;

    import app.repo.User.CustomUserDetailsService;
    import app.security.*;
    import app.security.filters.StatelessAuthenticationFilter;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.core.annotation.Order;
    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.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

    import javax.sql.DataSource;

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true)
    @Order(2)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

        private static PasswordEncoder encoder;

        @Autowired
        private TokenAuthenticationService tokenAuthenticationService;

        @Autowired
        private UserDetailsService customUserDetailsService;

        @Autowired
        private RESTAuthenticationEntryPoint authenticationEntryPoint;
        @Autowired
        private RESTAuthenticationFailureHandler authenticationFailureHandler;
        @Autowired
        private RESTAuthenticationSuccessHandler authenticationSuccessHandler;

        public WebSecurityConfig() {
            super(true);
        }

        @Autowired
        public void configureAuth(AuthenticationManagerBuilder auth,DataSource dataSource) throws Exception {
            auth.jdbcAuthentication().dataSource(dataSource);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/**").authenticated();
            http.csrf().disable();
            http.httpBasic();
            http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
            http.formLogin().defaultSuccessUrl("/").successHandler(authenticationSuccessHandler);
            http.formLogin().failureHandler(authenticationFailureHandler);
            http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
                    UsernamePasswordAuthenticationFilter.class);

        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService);
        }

        @Bean
        public TokenAuthenticationService tokenAuthenticationService() {
            tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", customUserDetailsService);
            return tokenAuthenticationService;
        }
    }

【问题讨论】:

  • 你为什么不发布一个堆栈跟踪?通常 Spring 会在调用其工厂方法之前完成配置类的自动装配,但循环依赖(或 Bean(Factory)PostProcessors 的依赖)可能会阻止这种情况。
  • TokenAuthenticationService 来自哪里?你能添加只接受一个参数和 Autowire userDetailService 的构造函数吗?

标签: java spring spring-security spring-boot


【解决方案1】:

您可以像这样将 userDetailsS​​ervice 定义为 TokenAuthenticationService 的直接依赖项:

@Bean
public TokenAuthenticationService tokenAuthenticationService(UserDetailsService userDetailsService) {
    tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", userDetailsService);
    return tokenAuthenticationService;
}

这样,Spring 将确保在创建 TokenAuthenticationService 时实例化并注入 UserDetailsS​​ervice。

【讨论】:

    【解决方案2】:

    您可以尝试使用 @Lazy 注释 tokenAuthenticationService()。尽管这有点不可预测,但未来对这个或相关 bean 的修改可能会让您想知道它为什么停止工作。

    最好将TokenAuthenticationService 声明为@Service 并在其中注入UserDetailsService

    作为旁注,最好不要将@Configuration 与应用程序代码混合以避免此类问题。

    更新 - 我不认为@Lazy 会在这里工作。由于您依赖于在处理 @Autowired bean 的过程中调用 @Bean 。

    为了让您的代码正常工作,应先设置@Autowired customUserDetailsS​​ervice,然后调用@Bean 方法,然后再设置@Autowired tokenAuthenticationService。

    【讨论】:

      猜你喜欢
      • 2019-05-17
      • 2021-07-22
      • 2023-01-17
      • 2019-10-19
      • 2017-12-22
      • 2017-07-24
      • 2014-04-16
      • 2017-10-31
      • 1970-01-01
      相关资源
      最近更新 更多