【问题标题】:Spring fails to autowire repositorySpring无法自动装配存储库
【发布时间】:2015-08-18 08:41:24
【问题描述】:

我对 Spring 自动装配有疑问。我正在尝试使用 Autowire 将存储库注入到身份验证服务中,顺便说一下,当我将其注入控制器时,它已经可以工作了。为了进一步参考,我正在添加相关代码和错误。

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>Restful Web Application</display-name>


     <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            enterprise.util.SpringSecurityConfig
        </param-value>
    </context-param>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>


    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>restEnterprise</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>restEnterprise</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>




</web-app>

restEnterpise-servlet.xml -- EmployeeRepository 在 dbService 中

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="enterprise.service" />
    <context:component-scan base-package="enterprise.controller" />
    <context:component-scan base-package="enterprise.util" />
    <context:component-scan base-package="dbService" />

    <mvc:annotation-driven />

</beans>

SpringSecurityConfig.java

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    private final TokenAuthenticationService tokenAuthenticationService; //handles adding auth token to response and checking for auth header in requests
    private final EmployeeDetailsService employeeDetailsService;
    public SpringSecurityConfig() {
        super(true);
        tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets");
        employeeDetailsService = new EmployeeDetailsService();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
      web
        .debug(true);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().and()
                .anonymous().and()
                .servletApi().and()
                .headers().cacheControl().and().and()
                .authorizeRequests()

                // Allow anonymous logins
                .antMatchers("/auth/**").permitAll()

                // All other request need to be authenticated
                .anyRequest().authenticated().and()

                // Custom Token based authentication based on the header previously given to the client
                .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    }

//http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.html

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

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

    @Bean
    @Override
    public EmployeeDetailsService userDetailsService() { 
        return employeeDetailsService;
    }

//--------------

    @Bean
    public TokenAuthenticationService tokenAuthenticationService() {
        return tokenAuthenticationService;
    }
}

EmployeeDetailsS​​ervice.java

@Component
public class EmployeeDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {

    @Autowired
    private EmployeeRepository employeeRep;

    @Override
    public final UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Employee employee = employeeRep.findByLogin(username);
        if (employee == null) {
            throw new UsernameNotFoundException("Employee not found");
        }
        List<GrantedAuthority> authorities = buildUserAuthority(employee.getRole());
        return buildUserForAuthentication(employee, authorities);
    }

    // Converts Employee to
    // org.springframework.security.core.userdetails.User
    private User buildUserForAuthentication(Employee user, 
        List<GrantedAuthority> authorities) {
        return new User(user.getLogin(), user.getPassword(), 
            true, true, true, true, authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(String userRole) {

        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        setAuths.add(new SimpleGrantedAuthority("ROLE_" + userRole.toUpperCase()));

        List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

        return Result;
    }

}

部署期间出错

2015-08-18 10:15:34,389 ERROR [org.jboss.as.controller.management-operation]     (management-handler-thread - 1) JBAS014613: Operation ("redeploy") failed - address: ([("deployment" => "enterprise.war")]) - failure description: {"JBAS014671: Failed services" => {"jboss.undertow.deployment.default-server.default-host./enterprise" => "org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./enterprise: Failed to start service
    Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDetailsService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dbService.dao.EmployeeRepository enterprise.service.EmployeeDetailsService.employeeRep; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [dbService.dao.EmployeeRepository] 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)}

正如我所说的 - 当我在控制器中使用它而不是在 EmployeeDetailsS​​ervice 中使用它时,这个自动装配工作。

【问题讨论】:

  • 实现/扩展dbService.dao.EmployeeRepository的类在哪里?
  • dbService.dao.EmployeeRepository 是否被注释为存储库?
  • 为什么要使用 new 来实例化 EmployeeDetailsS​​ervice.?使用 new 在 spring 容器之外创建一个实例
  • EmployeeRepository 是 JPA 接口。正如我所说,它在 RestController 中使用时一直在工作,所以我认为问题不在于这一方面。 @jozzy 我明白了!确实可能是这样。我还要如何实例化它?通过在 servlet 中将其声明为 bean?

标签: java xml spring spring-mvc


【解决方案1】:

不要使用 new 实例化 EmployeeService,你应该让 spring 容器来做实例化和连接。

您可以将您的员工服务自动连接为

 @AutoWired
 private final EmployeeDetailsService employeeDetailsService;

并从构造函数中删除新的实例化,并从 userDetailsService() 方法中删除 @Bean 注释

更新

如果你有一个主要的 spring 上下文 xml 将它导入到配置类中,如下所示

@Configuration
@ImportResource("restEnterpise-servlet.xml")
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter

如果你没有任何spring xml,你可以添加componentscan注解来发现spring组件@ComponentScan

【讨论】:

  • 当我做你的修复时,我得到ERROR Context initialization failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityConfig': Injection of autowired dependencies failed; (...) Could not autowire field: private enterprise.service.EmployeeDetailsService enterprise.util.SpringSecurityConfig.employeeDetailsService;(...)No qualifying bean of type [enterprise.service.EmployeeDetailsService] found for dependency:(...) 看起来 G. Trubach 是对的。这是加载内容的问题。
  • 非常感谢!您的更新和原始帖子帮助我解决了这个问题
【解决方案2】:

如果您的存储库扩展了JpaRepository,那么您需要在EmployeeDetailsService 中使用@Resource 代替@Autowired

【讨论】:

  • 存储库扩展了 CRUDRepository
【解决方案3】:

This link will be helpfull.

您在restEnterpise-servlet.xml 中声明的服务,并且您想使用EmployeeRepository。但是在您的 servlet 配置之前加载了安全配置。因此,您需要创建另一个 spring 配置,其中将声明所有组件扫描,并将在安全配置之前加载。 例如 spring-config.xml

 <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="enterprise.service" />
    <context:component-scan base-package="enterprise.controller" />
    <context:component-scan base-package="enterprise.util" />
    <context:component-scan base-package="dbService" />

    <mvc:annotation-driven />

</beans>

web.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-config.xml
            enterprise.util.SpringSecurityConfig
        </param-value>
    </context-param>

希望对你有帮助。

【讨论】:

  • 是的,可能是这样。问题是,当我使用您的解决方案时,我得到了2015-08-18 12:06:49,467 INFO [org.springframework.web.context.support.AnnotationConfigWebApplicationContext] (MSC service thread 1-1) No annotated classes found for specified class/package [/WEB-INF/spring-beforeSecurityLoad.xml。你知道为什么它找不到任何东西吗?
  • spring-beforeSecurityLoad.xml 中有什么内容?尝试阅读此post
  • 我只是从 servlet 配置中复制并粘贴了组件扫描。
  • 尝试阅读此post。也许会有帮助。
  • 注解配置的问题。
猜你喜欢
  • 2017-03-28
  • 2019-02-28
  • 1970-01-01
  • 2014-03-22
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 2015-02-22
相关资源
最近更新 更多