一、问题描述
eclipse集成环境,spring 4.1.3.RELEASE + cxf 2.5.0框架,开发的Webservice客户端程序。在eclipse开发环境下运行正常,导出runnable jar包时出现如下异常:
java.lang.NullPointerException: null
at org.apache.cxf.wsdl11.WSDLServiceFactory.(WSDLServiceFactory.java:92)
at org.apache.cxf.jaxws.ServiceImpl.initializePorts(ServiceImpl.java:204)
at org.apache.cxf.jaxws.ServiceImpl.(ServiceImpl.java:148)
at org.apache.cxf.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:90)
at javax.xml.ws.Service.(Unknown Source) ~[na:1.7.0_79]
二、初步分析
既然代码工程在eclipse能够正常运行,导出包后出现空指针异常,应该是打包的问题,runnable jar打包对依赖库的处理方式有三种,如下图所示:
Library handing的三种处理方式解释如下:
1、Extract required libraries into generated JAR。
把项目中所有的依赖jar包内的class,xml等文件都拆开,放在jar的对应的目录中,即导出的jar文件是一个独立的,没有其他依赖jar包的文件,因为依赖的jar包已经全部拆散了。
2、Package required libraries into generated JAR。
把项目中所有的import jar都包在jar的根目录下,还是以依赖包的形式存在,形成一个 完整的jar文件。
3、Copy required libraries into a sub-folder next to the generated JAR。
把项目中所有import jar放在jar外面独立的一个文件夹,jar包内只有工程的源码编译的class文件和其他配置文件,这种方式导出结果有两个:一个工程jar包和一个文件夹。
以上三种方式,生成的效果基本相同,细心地可以发现,这三种方式生成的MANIFEST.MF文件是不一样的。
这三种方式导出的jar包,执行命令都是 java -jar xxx.jar。
我们之前选的是第一种,运行后发现有异常,现在我们选第二种或第三种,试运行一下,OK。
由此可知,是第一种打包方式出现了问题,导致运行报错。
三、解决方案
显而易见,打包时选第二种或第三种方式即可。
四、问题深究 前面提到第一种打包方式导致异常,但具体是什么原因导致的呢? 这样我们必须调试这个发布包,确定是哪行代码导致的异常,这种情况我们需要用到远程调试,启动命令该这样写了: java -Xdebug -XRunjdwp;transport=dt_socket,server=y,address=8000 -jar test.jar 监听8000端口(可以改成其他的),test.jar为示例jar包。 调试的详细过程就不赘述了,经过远程调试分析可知错误的原因:cxf框架有多个jar包都有bus-extensions.txt文件,打包过程中是做的覆盖操作,这点很重要,所有相同目录,相同名称的文件会被覆盖,例如cxf框架jar包内的META-INF\cxf目录下就有几个相同名称的文件,导致上述出现的错误。 有bus-extensions.txt的jar包: cxf-rt-core-2.5.0.jar cxf-rt-frontend-jaxws-2.5.0.jar cxf-rt-bindings-xml-2.5.0.jar cxf-rt-ws-addr-2.5.0.jar cxf-rt-transports-http-2.5.0.jar cxf-rt-bindings-soap-2.5.0.jar 共找到6个 综上所述,导致包运行异常的原因还是出在打包的过程中,由于众多jar包文件存在重名可能性较大,尤其是META-INF目录下,我们做不到逐一探查,建议慎重使用该打包方式。