简体   繁体   English

Spring Autowired 空指针异常

[英]Spring Autowired Null Pointer Exception

I'm having some problems developing a very simple web application using Spring-MVC (4.2.5), Spring-Security (4.0.3) and MongoDB.我在使用 Spring-MVC (4.2.5)、Spring-Security (4.0.3) 和 MongoDB 开发一个非常简单的 Web 应用程序时遇到了一些问题。

I'm trying to implement a custom authentication provider, in order to login the user via database, using DAO pattern.我正在尝试实现自定义身份验证提供程序,以便使用 DAO 模式通过数据库登录用户。 Although it seems to have initialized properly the application context, I'm having Null Pointer Exception on the Autowired variables (CustomerDao and CustomUserDetailsService).虽然它似乎已经正确初始化了应用程序上下文,但我在 Autowired 变量(CustomerDao 和 CustomUserDetailsS​​ervice)上遇到了空指针异常。

web.xml网页.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>AcmeSpring</display-name>
    <servlet>
        <servlet-name>SpringController</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringController</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-security.xml
        </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>
    </filter-mapping>
</web-app>

spring-mvc.xml spring-mvc.xml

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

    <mvc:annotation-driven />
    <context:component-scan base-package="controller" />
    <context:component-scan base-package="model" />
    <context:component-scan base-package="dao" />
    <context:component-scan base-package="service" />

    <mvc:resources mapping="/resources/**" location="/resources/" />

    <bean id="templateResolver"
        class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
        <property name="prefix" value="/WEB-INF/html/" />
        <property name="suffix" value=".html" />
        <property name="templateMode" value="HTML5" />
    </bean>

    <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver" />
    </bean>

    <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine" />
        <property name="order" value="1" />
    </bean>

    <mongo:db-factory id="mongoDbFactory" host="localhost"
        port="27017" dbname="AcmeSpring" />

    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg ref="mongoDbFactory" />
    </bean>

    <bean id="customerDao" class="dao.CustomerDaoImpl">
    </bean>
</beans>

spring-security.xml spring-security.xml

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

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

    <http auto-config="true">
        <intercept-url pattern="/user/**" access="hasRole('USER')" />
        <form-login authentication-failure-url="/login" login-page="/login"
            login-processing-url="/login" default-target-url="/user" />
        <logout invalidate-session="true" success-handler-ref="logoutSuccessHandler" />
    </http>

    <authentication-manager>
        <authentication-provider ref="customAuthenticationProvider" />
    </authentication-manager>

    <beans:bean id="customUserDetailsService" class="service.CustomUserDetailsService">
    </beans:bean>

    <beans:bean id="customAuthenticationProvider" class="service.CustomAuthenticationProvider">
    </beans:bean>

    <beans:bean id="logoutSuccessHandler" class="service.CustomLogoutSuccessHandler">
    </beans:bean>
</beans:beans>

CustomAuthenticationProvider自定义身份验证提供程序

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    CustomUserDetailsService userDetails;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        System.out.println(userDetails == null);

        Customer customer = userDetails.loadUserByUsername(username);

        if(customer == null) {
            throw new BadCredentialsException("Username errato");
        }

        if(!password.equals(customer.getPassword())) {
            throw new BadCredentialsException("Password errata");
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(customer.getRole()));

        return new UsernamePasswordAuthenticationToken(customer, password, authorities);
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return clazz.equals(UsernamePasswordAuthenticationToken.class);
    }
}

CustomUserDetailsService自定义用户详细信息服务

@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private CustomerDao customerDao;

    @Override
    public Customer loadUserByUsername(String username) throws UsernameNotFoundException {
        return customerDao.findCustomerByUsername(username);
    }
}

CustomerDaoImpl CustomerDaoImpl

@Repository
public class CustomerDaoImpl implements CustomerDao {
    private static final String COLLECTION = "Customer";
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void create(Customer customer) {
        this.mongoTemplate.insert(customer, COLLECTION);
    }

    @Override
    public Customer findCustomerByUsername(String username) {
        Query query = new Query();
        query.addCriteria(Criteria.where("username").is(username));
        System.out.println(query.toString());
        return this.mongoTemplate.findOne(query, Customer.class);
    }
}

stack trace堆栈跟踪

java.lang.NullPointerException
    service.CustomUserDetailsService.loadUserByUsername(CustomUserDetailsService.java:18)
    service.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:32)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)

Where am I wrong?我哪里错了? Thank you in advance.先感谢您。

EDIT: I don't have initialized the autowired variable manually, just bad paste, I've edited my code.编辑:我没有手动初始化自动装配变量,只是粘贴不好,我已经编辑了我的代码。

EDIT2: as suggested by @iMysak I remove the customerDao bean declaration from spring-mvc.xml and the 3 services bean declaration from spring-security.xml EDIT2:按照@iMysak 的建议,我从 spring-mvc.xml 中删除了 customerDao bean 声明,从 spring-security.xml 中删除了 3 个服务 bean 声明

new stack trace新的堆栈跟踪

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#1' while setting bean property 'sourceList' with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#1': Cannot create inner bean '(inner bean)#5adbfd3' of type [org.springframework.security.web.authentication.logout.LogoutFilter] while setting constructor argument with key [4]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5adbfd3': Cannot resolve reference to bean 'logoutSuccessHandler' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'logoutSuccessHandler' is defined
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:753)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4853)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5314)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#1': Cannot create inner bean '(inner bean)#5adbfd3' of type [org.springframework.security.web.authentication.logout.LogoutFilter] while setting constructor argument with key [4]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5adbfd3': Cannot resolve reference to bean 'logoutSuccessHandler' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'logoutSuccessHandler' is defined
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:129)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:634)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 26 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5adbfd3': Cannot resolve reference to bean 'logoutSuccessHandler' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'logoutSuccessHandler' is defined
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:634)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:299)
    ... 40 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'logoutSuccessHandler' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 48 more

I also tried adding aop, tx and expressions dependencies as suggested here but I get the above stack trace我还尝试按照此处的建议添加 aop、tx 和表达式依赖项,但我得到了上面的堆栈跟踪

It could be problem with using multiple context:component-scan tags.使用多个context:component-scan标签可能会出现问题。 Please try next:请尝试下一步:

<context:component-scan base-package="controller model dao service" />

instead of declaration them separately.而不是分别声明它们。

You made the classic Spring bean mistake.您犯了典型的 Spring bean 错误。 You annotated the bean:您注释了 bean:

@Autowired
CustomUserDetailsService userDetails;

You called new:你打电话给新的:

userDetails = new CustomUserDetailsService();

It's either under Spring control or yours.它要么在 Spring 的控制之下,要么在你的控制之下。 The moment you called new, it was out of Spring's hands.你调用 new 的那一刻,它就脱离了 Spring 的控制。

If you want Spring to auto wire dependencies, you cannot call new to initialize the reference.如果您希望 Spring 自动连接依赖项,则不能调用 new 来初始化引用。 Let Spring do it.让春天来做。

Can you try getting rid of你能试着摆脱吗

<beans:bean id="customAuthenticationProvider" class="service.CustomAuthenticationProvider">
</beans:bean>

and

<beans:bean id="customUserDetailsService" class="service.CustomUserDetailsService">
    </beans:bean>

I think the XML declaration might be redundant with the annotation declaration and component scan我认为 XML 声明可能与注释声明和组件扫描是多余的

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

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