繁体   English   中英

spring @Autowired 给出 NullPointerException

[英]spring @Autowired giving NullPointerException

我正在使用 Hibernate 学习 Spring 并通过简单的登录制作一个演示项目。 我坚持@Autowired 给出NullPointerException。 我没有得到它背后的正确原因,但我想这是因为 Spring 无法自己实例化 bean。

只有当我使用customAuthenticationProvider登录时才会出现问题。 如果我使用默认的<user-service>用户名和密码作为管理员,代码运行良好。

这是我的代码,

网页.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

  <display-name>Archetype Created Web Application</display-name>

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

  <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/</url-pattern>
  </servlet-mapping>

  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        /WEB-INF/spring-security.xml
      </param-value>
  </context-param>

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

<!-- Spring Security -->
  <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>
  </filter-mapping>

  <context-param>
      <param-name>log4jConfigLocation</param-name>
      <param-value>classpath:log4j.properties</param-value>
  </context-param>

  <listener>
      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>

</web-app>

调度程序-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<mvc:annotation-driven />
<context:component-scan base-package="com.ssb" />
<context:annotation-config />

<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.ssb.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security.xsd">

<http pattern="/resources/**" security="none" />

<http auto-config="true" use-expressions="true">
    <http-basic/>
    <intercept-url pattern="/login" access="permitAll"/>
    <intercept-url pattern="/**" access="isAuthenticated()" />
    <form-login login-page="/login" default-target-url="/home"
        authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
        username-parameter="username" password-parameter="password" />
    <logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout"/>
    <!-- enable csrf protection -->
    <csrf/>
</http>

<beans:bean id="customAuthenticationProvider"
    class="com.ssb.components.CustomAuthenticationProvider">
</beans:bean>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="admin" password="admin" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
    <authentication-provider ref="customAuthenticationProvider">
    </authentication-provider>
</authentication-manager>

</beans:beans>

CustomAuthenticationProvider.java

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    public AuthService authService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authService.authenticateUser(authentication);
        // it never gets to this line as authService is null
        return new UsernamePasswordAuthenticationToken(authentication.getName(), "");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

}

主控制器.java

@Controller
public class HomeController {

  @Autowired
  HomeService homeService;

  @Autowired
  SessionFactory sessionFactory;

  @RequestMapping(value="/home", method=RequestMethod.GET)
  public String home(Model model){

      User user = new User();
      user.setName("test");
      user.setPassword("test");
      homeService.save(user);

      return "home";
  }

  @RequestMapping(value= "/login", method=RequestMethod.GET)
  public ModelAndView login(
          @RequestParam(value = "error", required = false) String error,
          @RequestParam(value = "logout", required = false) String logout) throws IOException {

          ModelAndView model = new ModelAndView();
          if (error != null) {
              model.addObject("error", "Invalid username and password!");
          }
          if (logout != null) {
            model.addObject("msg", "You've been logged out successfully.");
          }
          model.setViewName("login");
          return model;
      }

}

AuthServiceImpl.java

@Service
public class AuthServiceImpl implements AuthService{

  @Autowired
  HomeDao homeDao;

  @Transactional
  public void authenticateUser(Authentication authentication) {
    homeDao.authenticateUser(authentication);
  }

}

家道.java

@Repository
public class HomeDao {

  @Autowired
  SessionFactory sessionFactory;

  public void save(User user){
      Session session = sessionFactory.getCurrentSession();
      Roles role = (Roles) session.get(Roles.class, 1);
      user.setRole_id(role);
      session.save(user);
  }

  public void authenticateUser(Authentication authentication) {
      Criteria criteria =  sessionFactory.getCurrentSession().createCriteria(User.class);
      criteria.add(Restrictions.eq("username", authentication.getPrincipal().toString()));
      criteria.add(Restrictions.eq("password", authentication.getCredentials().toString()));
      @SuppressWarnings("unchecked")
      List<User> result = criteria.list();
      System.out.println(result);

  }

}

错误

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/springAct] threw exception
java.lang.NullPointerException
at com.ssb.components.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:20)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:495)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:767)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1347)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

您正在加载spring-security.xml作为 spring 根上下文,并且在此上下文中没有任何context:component-scan ,因此在尝试在根上下文中使用@Autowired bean 时收到 NPE 是绝对正常的,它具有在 mvc 上下文中加载,这是一个子上下文。

您可以在此答案中获得更多信息: https : //stackoverflow.com/a/30640404/4190848

为了避免这种错误,我将执行以下操作:

  1. 在您的dispatcher-servlet.xml只需映射context:component-scan @Controller映射的@Controller型。

例如:

<context:component-scan base-package="com.ssb.controller" />
  1. 由于您仅使用spring-security.xml作为根上下文,因此您应该映射任何其他用@Service@Repository@Component映射的@Component

例如:

<context:component-scan base-package="com.ssb.repositories" />
<context:component-scan base-package="com.ssb.services" />
  1. 同样,您应该将dispatcher-servlet.xml定义的一些 bean 移动到spring-security.xml

就这些:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.ssb.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

因此,生成的dispathcer-servlet.xmlspring-security.xml应该是这样的,只在context:component-scan base-packages设置正确context:component-scan base-packages

调度员.servlet.xml:

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

    <mvc:annotation-driven />
    <context:component-scan base-package="com.ssb.controller" />
    <context:annotation-config />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

弹簧security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://www.springframework.org/schema/security"
  xmlns:tx="http://www.springframework.org/schema/tx" 
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:component-scan base-package="com.ssb" />

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
        <beans:property name="username" value="root" />
        <beans:property name="password" value="admin" />
    </beans:bean>

    <beans:bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="packagesToScan" value="com.ssb.model" />
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
                </beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
     </beans:bean>

    <tx:annotation-driven transaction-manager="transactionManager" />

    <beans:bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="sessionFactory" />
    </beans:bean>

    <http pattern="/resources/**" security="none" />

    <http auto-config="true" use-expressions="true">
        <http-basic />
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/**" access="isAuthenticated()" />
        <form-login login-page="/login" default-target-url="/home"
        authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
        username-parameter="username" password-parameter="password" />
        <logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout" />
        <!-- enable csrf protection -->
        <csrf />
    </http>

    <beans:bean id="customAuthenticationProvider"
        class="com.ssb.components.CustomAuthenticationProvider">
    </beans:bean>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
        <authentication-provider ref="customAuthenticationProvider">
        </authentication-provider>
    </authentication-manager>

</beans:beans>

尝试在 dispatcher-servlet.xml 的末尾放置 context:component-scan base-package="com.ssb" 它可能会起作用,因为将 bean 放入 ioc 容器时它需要依赖项,因此在创建 AuthService bean 时它需要依赖项类未在 IOC 容器中创建。确保所有依赖项配置正确顺序

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM