今天在进行struts2加spring整合的过程中,出现了空指针错误,错误信息如下“:
java.lang.NullPointerException
com.action.UserAction.deal(UserAction.java:31) com.action.UserAction$$FastClassBySpringCGLIB$$898dd58c.invoke() org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) com.action.UserAction$$EnhancerBySpringCGLIB$$b82da6c_2.deal() sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450) com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252) org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167) com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265) org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68) com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:249) com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171) com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189) com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246) org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54) org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:562) org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77) org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218) org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506) org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962) org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2536) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2525) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) java.lang.Thread.run(Thread.java:745)
开始我以为是配置问题导致struts2没有整合spring,然后在myeclipse上进行了单元测试,发现单元测试结果正常,action的usermanager能正常注入,说明此时action的确是由spring产生的,但是在web上就会出现空指针错误。在网上查阅大量资料后发现网上说的各种情况都不符合,最后查到说action的usermanager的变量名要和usermanager类在spring容器中的ID相同才行,只有action的usermanager的变量名和usermanager类的ID相同时 才不会出错,如果变量名和ID不相同,即使在action的usermanager的set方法上使用resource注解并指定usermanager类的ID,也会出错。比如action的变量名为user,注解为resource(name="userManager"),usermanager类的ID为userManager,也还是会报错,只有把变量名改成userManager或把usermanager类的ID改成user才能去掉异常。
今天偶然发现在action中的变量名和对应类的ID相同的情况下,即使没有加resource也能成功注入,也就是其实userManager的注入不是因为rrsource.其实,在struts2-spring-plugin中有一个autowire的设置,
这个autowire的值默认是设为name,说明struts2和spring整合后会根据action的属性的名字去spring的容器里查找ID和它一样的类,如果找到就会自动装配上。这也是为什么去掉resource后还能成功注入的原因。那为什么resource不起作用呢?在网上查找后发现,struts.xml配置文件里的action配置有问题,在正常情况下的配置是这样的:
<action name="user" class="com.action.UserAction" >
<result>/front/registersuccess.jsp</result>
<result name="fail">/front/registerfail.jsp</result>
<result name="list">/front/userlist.jsp</result>
</action>
class属性填入的是包名加类名,但是整合之后应该是这样:
<action name="user" class="userAction" >
<result>/front/registersuccess.jsp</result>
<result name="fail">/front/registerfail.jsp</result>
<result name="list">/front/userlist.jsp</result>
</action>
在class里填入的应该是UserAction在spring容器里的ID名,其实就是把com.action.UserAction改成userAction,就行了。然后在UserAction中的属性的set方法里加上resource注解,这样即使属性名和类名不一样也能成功注入。
这其实是两种不同的设置action的方式,一种是struts配置文件中class还是用全限定名,struct自己产生action对象,然后利用spring插件的自动装配功能完成注入,也就是autowire方式,这种方法不用写spring注释(component,scope,resource)。另一种则是把action也交给spring管理,由spring产生和装配,这时的XML配置文件中的class要使用action类在spring容器中的ID名,要写component,scope,resouce。
另外,注意使用autowire方式注入时可能发生一种难以发现的异常,就是spring插件把类型不同但名称相同的类租入了导致类型转换错误,比如action类里有一User类型的变量叫user,spring容器中有一UserManager类型的类的ID也叫user,spring就会把UserManager付给User,然后抛出类型错误异常,提示不能从UserManager类转成User类。