Spring Autowired空指针异常
Posted
技术标签:
【中文标题】Spring Autowired空指针异常【英文标题】:Spring Autowired Null Pointer Exception 【发布时间】:2017-07-02 02:54:15 【问题描述】:我在使用 Spring-MVC (4.2.5)、Spring-Security (4.0.3) 和 MongoDB 开发一个非常简单的 Web 应用程序时遇到了一些问题。
我正在尝试实现一个自定义身份验证提供程序,以便使用 DAO 模式通过数据库登录用户。虽然它似乎已经正确初始化了应用程序上下文,但我在 Autowired 变量(CustomerDao 和 CustomUserDetailsService)上有空指针异常。
web.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
<?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
<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
@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);
堆栈跟踪
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)
我哪里错了? 提前谢谢你。
编辑:我没有手动初始化自动装配变量,只是粘贴不好,我已经编辑了我的代码。
EDIT2:按照@iMysak 的建议,我从 spring-mvc.xml 中删除了 customerDao bean 声明,并从 spring-security.xml 中删除了 3 个服务 bean 声明
新的堆栈跟踪
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
我还尝试按照here 的建议添加 aop、tx 和表达式依赖项,但我得到了上面的堆栈跟踪
【问题讨论】:
尝试在 spring-security.xml 中添加这一行:使用多个context:component-scan
标签可能会出现问题。请尝试下一步:
<context:component-scan base-package="controller model dao service" />
而不是单独声明它们。
【讨论】:
即使按照您的建议更改组件扫描也会出现同样的错误 @andy 你能把这些遗漏的 bean 声明从 spring-security.xml 中移出并放入 spring-mvc.xml 吗? customUserDetailsService 和其他人。只是为了确保 我试过了,但我得到一个“创建名为 'org.springframework.security.filterChains' 的 bean 时出错” 如果在 context:component-scan 下使用定义 dao 和 service 你甚至不应该声明它们在 xml 中,因此您甚至可以从 xml 中删除它们。您使用 filterChains 到底遇到了什么错误? 也请关注***.com/questions/19099289/…【参考方案2】:你犯了经典的 Spring bean 错误。你注释了 bean:
@Autowired
CustomUserDetailsService userDetails;
你叫新人:
userDetails = new CustomUserDetailsService();
它要么在 Spring 控制之下,要么在你的控制之下。你调用 new 的那一刻,它就脱离了 Spring 的控制。
如果你想让 Spring 自动连接依赖,你不能调用 new 来初始化引用。让 Spring 来做吧。
【讨论】:
我的代码中并没有真正的 userDetails = new CustomUserDetailsService(),抱歉粘贴不好:我试图删除所有 Autowired 注释并手动初始化 dao 和服务,回去我忘记删除该行。我知道如果这些是自动装配的,我不必初始化变量。我已经编辑了我的问题【参考方案3】:你可以尝试摆脱
<beans:bean id="customAuthenticationProvider" class="service.CustomAuthenticationProvider">
</beans:bean>
和
<beans:bean id="customUserDetailsService" class="service.CustomUserDetailsService">
</beans:bean>
我认为 XML 声明可能与注解声明和组件扫描是多余的
【讨论】:
删除这些行我得到一个“创建名称为 'org.springframework.security.filterChains' 的 bean 时出错”等。以上是关于Spring Autowired空指针异常的主要内容,如果未能解决你的问题,请参考以下文章
使用服务的Spring安全性不会自动赋予依赖关系并提供空指针异常
使用@Autowired注解无法注入(使用service报空指针异常)的问题解决,亲测可用!
SpringBoot整合WebSocket时,自动注入Service层报错空指针异常的解决方案
SpringBug记录 -- java.lang.NullPointerException在Spring单元测试中遇到的空指针异常及依赖注入异常总结