Search code examples
javaspringspring-bootspring-ioc

Autowire doesn't work for custom UserDetailsService in Spring Boot


The spring boot apps starts up, tomcat runs, and then it throws an error before finally dying.

Error

Running my app gives me this Autowired error:

2016-07-29 02:18:24.737 ERROR 44715 --- [  restartedMain] o.s.boot.SpringApplication               : Application startup failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private myapp.MyUserDetailsService myapp.WebSecurityConfig.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [myapp.MyUserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]

Details

My Security configuration:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
        .antMatchers("/", "/register").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/")
        .permitAll()
        .and()
        .logout()
        .permitAll();
}

@Autowired
private MyUserDetailsService userDetailsService;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
}

}

MyUserDetails:

@Service
@Transactional
public class MyUserDetailsService implements UserDetailsService {

@Autowired
private UserRepository userRepository;


public MyUserDetailsService() {
        super();
}

@Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
        User user = userRepository.findByUserName(userName);
        if (user == null) {
                return null;
        }
        List<GrantedAuthority> auth = AuthorityUtils
                                      .commaSeparatedStringToAuthorityList("ROLE_USER");
        String password = user.getPassword();
        return new org.springframework.security.core.userdetails.User(userName, password,
                                                                      auth);
}



}

You may find full source code at Git Repo


Solution

  • I've tried your project at commit 3b9a6a2e, and the error is actually different:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private myapp.MyUserDetailsService myapp.WebSecurityConfig.userDetailsService; nested exception is java.lang.IllegalArgumentException: Can not set myapp.MyUserDetailsService field myapp.WebSecurityConfig.userDetailsService to com.sun.proxy.$Proxy80

    Which makes your question a duplicate of Spring can't create beans. Solution: replace

    @Autowired
    private MyUserDetailsService userDetailsService;
    

    with

    @Autowired
    private UserDetailsService userDetailsService;
    

    Your solution (removing @Transactional) works because without @Transactional there is no reason for Spring to wrap MyUserDetailsService in a proxy.