0
votes

I have a project based on SpringMVC 5 and an error happened when I tried to run it on JBoss EAP 7.3.

14:33:14,134 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ServerService Thread Pool -- 99) Creating shared instance of singleton bean 'userDetailsService'

14:33:14,140 ERROR [org.springframework.web.context.ContextLoader] (ServerService Thread Pool -- 99) Context initialization failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration: Bean instantiation via factory method failed;......nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.aaa.bbb.security.service.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Here's the code of class "UserDetailsServiceImpl":

public class UserDetailsServiceImpl implements UserDetailsService {
    
    @Autowired
    private UserService userService;

    @Autowired 
    private SessionUtils sessionUtils;
    
    @Override
    public UserDetails loadUserByUsername(String userID) throws UsernameNotFoundException {
        User user = userService.get(userID);
        
        if (user == null) throw new UsernameNotFoundException("Could not find user");
        sessionUtils.expireUserSessions(user.getUser_name());   // Force expire other session
        
        return new UserDetailsInfo(user);
    }
}

And here's the code of class "UserService":

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User get(String id) {
        return userRepository.findById(id).get();
    }

    public User getuUserByUsername(String user_name) {
        return userRepository.getuUserByUsername(user_name);
    }

    public int incLoginErrorCount(String id) {
        return userRepository.incLoginErrorCount(id);
    }

    public int resetLoginErrorCount(String id) {
        return userRepository.resetLoginErrorCount(id);
    }

    public int lockCount(String id) {
        return userRepository.lockCount(id);
    }
    
    public int changeUPassword(String id, String password) {
        return userRepository.changeUPassword(id, password);
    }
}

And I'm using "WebAppInitializer":

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    private String TMP_FOLDER = "/tmp";
    private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024;

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { WebSecurityConfig.class};
    }
    
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
    
    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new HiddenHttpMethodFilter(), new MultipartFilter(),
                new OpenEntityManagerInViewFilter() };
    }

    @Override
    protected void registerDispatcherServlet(ServletContext servletContext) {
        super.registerDispatcherServlet(servletContext);
        servletContext.addListener(new HttpSessionEventPublisher());

    }

    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {

        MultipartConfigElement multipartConfigElement = new MultipartConfigElement(TMP_FOLDER, MAX_UPLOAD_SIZE,
                MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2);
        registration.setMultipartConfig(multipartConfigElement);

    }
}

To call "WebMvcConfig":

@ComponentScan(basePackages = {"com.aaa.bbb"})
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(100000);
        return multipartResolver;
    }
    
    @Override
    public void configureDefaultServletHandling(
      DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**", "/resources/**", "/resources/**", "/webjars/**", "/log/**")
        .addResourceLocations("classpath:/css/", "classpath:/js/", "classpath:/json/", "/webjars/", "/META-INF/");
    }

    @Bean
    public MessageSource messageSource() {

        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setBasenames("message/messages");
        source.setUseCodeAsDefaultMessage(true);
        source.setDefaultEncoding("UTF-8");

        return source;
    }
}

If @ComponentScan worked, this error should not happen. Thank you!

1

1 Answers

1
votes

I think you should use @Service annotation on the UserDetailsServiceImpl class too. Since it is not annotated, componentScan doesn't know that it should autowire the services inside it. So UserDetailsServiceImpl class should look like this.

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
private UserService userService;

@Autowired 
private SessionUtils sessionUtils;

@Override
public UserDetails loadUserByUsername(String userID) throws UsernameNotFoundException {
    User user = userService.get(userID);
    
    if (user == null) throw new UsernameNotFoundException("Could not find user");
    sessionUtils.expireUserSessions(user.getUser_name());   // Force expire other session
    
    return new UserDetailsInfo(user);
    }
}