最近使用springboot開發項目,使用到了依賴注入,頻繁的碰到注入的對象報空指針,錯誤如下
java.lang.NullPointerException: null at com.mayihc.audit.controller.MaterialNkDetailController.download(MaterialNkDetailController.java:72) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387) at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Unknown Source)
第一次碰見的情況是:在new出來的對象中使用@Autowired來獲取注入的對象
DateCheckUtils dateCheckUtils = new DateCheckUtils();
我要在這個類中使用依賴注入,剛開始寫的是注入方式如下
public class DateCheckUtils { @Autowired private CompanyInfoService companyInfoService; @Autowired private MaterialNkDetailService materialNkDetailService; ......... }
這是會報空指針異常,后倆修改代碼就解決了問題,修改后的代碼如下
1、創建一個類實現ApplicationContextAware,用來獲取applicationContext 和bean
package com.mayihc.audit.core.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtils implements ApplicationContextAware{ private static ApplicationContext applicationContext = null; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if(SpringUtils.applicationContext == null){ SpringUtils.applicationContext = applicationContext; } } //獲取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } //通過name獲取 Bean. public static Object getBean(String name){ return getApplicationContext().getBean(name); } //通過class獲取Bean. public static <T> T getBean(Class<T> clazz){ return getApplicationContext().getBean(clazz); } //通過name,以及Clazz返回指定的Bean public static <T> T getBean(String name,Class<T> clazz){ return getApplicationContext().getBean(name, clazz); } }
2、在new出來的DateCheckUtils類中獲取ApplicationContext的實例
public class DateCheckUtils { //獲取ApplicationContext的實例 private ApplicationContext applicationContext = SpringUtils.getApplicationContext(); //通過applicationContext和反射機制來獲取對象 private CompanyInfoService companyInfoService = applicationContext.getBean(CompanyInfoService.class); private MaterialNkDetailService materialNkDetailService = applicationContext.getBean(MaterialNkDetailService.class); private MaterialNkLogbookService materialNkLogbookService = applicationContext .getBean(MaterialNkLogbookService.class); private MaterialNkLedgerService materialNkLedgerService = applicationContext.getBean(MaterialNkLedgerService.class); private MaterialGjChangeDetailService materialGjChangeDetailService = applicationContext .getBean(MaterialGjChangeDetailService.class); private MaterialGjLedgerService materialGjLedgerService = applicationContext.getBean(MaterialGjLedgerService.class); .....
}
這樣就可以獲取到要注入的對象
報空指針的原因:當對象聲明為bean組件的時候,他是交給spring容器去管理的,容器會幫你進行初始化;但是如果使用new方法來調用對象是=時,會跳過spring容器生成的對象,這是就無法進行初始化,所以在調用的時候就會出現對象為null,並且對象里面以注入方式引用的對象也為null,被聲明為bean對象的組件必修使用注入的方式進行調用。
上述的問題也可以通過將 DataCheckUtils dataCheckUtils=new DataCheckUtils();改為:
@Autowired
private DataCheckUtils dataCheckUtils;來實現
第二種碰見null的情況:在同一個類中只有某個方法在被前端調用的時候報null,其余方法都正常。
錯誤代碼如下
1 @RequestMapping("/download") 2 private void download(HttpServletResponse response, MaterialNkDetail materialNkDetail) throws Exception { 3 SysUser u = (SysUser) SecurityUtils.getSubject().getPrincipal(); 4 if(!"1".equals(u.getType())) { 5 materialNkDetail.setCompanyId(u.getCompanyInfoId()); 6 } 7 CompanyInfo companyInfo = companyInfoService.selectByPrimaryKey(u.getCompanyInfoId()); 8 if(companyInfo == null) { 9 companyInfo = new CompanyInfo(); 10 companyInfo.setFullName("全部車輛"); 11 } 12 ..... 13 }
當運行這個方法時,注入的對象總是報null,經排查后,此方法是用private修飾的,改為public修飾后就OK了。
原因:容器掃描bean生成代理類的時候,public和protected方法可以被正常代理,而private方法不會被正常代理,屬性的注入是在代理類中完成的,所以public和protected方法獲取的注入屬相是完成注入的屬性,private方法獲取的是為完成注入的屬性,所以是null