【问题标题】:spring @Autowired giving NullPointerExceptionspring @Autowired 给出 NullPointerException
【发布时间】:2018-07-15 06:25:55
【问题描述】:

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

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

这是我的代码,

web.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>

dispatcher-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;
    }

}

HomeController.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);
  }

}

HomeDao.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)

【问题讨论】:

  • A Spring @Autowired 不能是 null,如果您的应用程序甚至无法启动。如果您没有在 xml 中设置注释处理 context:component-scan 或 context:annotation-config,或者您正在自己创建新的 bean 实例,它只会是 null。在你的情况下,第一个看起来像这样。
  • @M.Deinum 请查看 dispatcher-servlet.xml 。 &lt;context:component-scan base-package="com.ssb" /&gt; 在那里。
  • 这是为DispatcherServlet 加载的上下文,而不是由ContextLoaerListener 加载的上下文,它们不会与Bean(Factory)PostProcessors 相互影响。

标签: java spring spring-mvc spring-security


【解决方案1】:

您正在加载 spring-security.xml 作为 spring 根上下文,并且在此上下文中没有任何 context:component-scan,因此在尝试在具有被加载在 mvc 上下文中,这是一个子上下文。

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

为避免此类错误,我会执行以下操作:

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

例如:

<context:component-scan base-package="com.ssb.controller" />
  1. 由于您只使用spring-security.xml 作为根上下文,因此您应该映射与@Service、@Repository 或@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.xml 和spring-security.xml 应该是这样的,只在context:component-scan base-packages 中设置正确的包:

dispatcher.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>

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"
  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>

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 您是否传递了您的原型注释所在的确切包名称。
    • 是的,我已经通过了确切的基础包“com.ssb”。
    猜你喜欢
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-06
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多