有时候我们在同一个方法调用多个webservice的时候,有可能会报数组下标越界问题,出现该问题主要是因为发布webservice时在service.xml使用了同样的schemaNamespace导致的。
问题重现:
(1)、在axis2中发布了两个webservice:query_log_lzj和insert_log_lzj:
并且这两个webservice的service.xml配置文件的schemaNamespace都是相同的:
(2)、在同一个方法中调用这两个服务,代码如下:
如果运行上面的main函数,将会得到如下错误:
原因分析:
后来通过跟踪cxf调用服务的源码发现了问题:
(1)、当cxf调用服务代码时,cxf会为每个服务在本地(我本地的生成目录:C:\Users\gosunAdmin\AppData\Local\Temp\org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory@69254fcd-1493881837654-src\test\lzj\com\dataservice)生成几个java文件(具体生成源码可以查看cxf-rt-databinding-jaxb-2.5.9-sources.jar包的DynamicClientFactory.java的createClient方法),应该是服务类的代理类,然后会把这几个java文件编译成class(class保存目录:C:\Users\gosunAdmin\AppData\Local\Temp\org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory@69254fcd-1493881837654-classes)(这些源码和编译后的class,在使用完的时候会马上删除):
每个服务cxf都会生成的java文件有如下几个:
其中有个ObjectFacroty的类,这个类的内容如下:
query_log_lzj服务的ObjectFactory内容如下:
insert_log_lzj服务的ObjectFactory内容如下:
问题就出在这个ObjectFactory类,当调用第一个服务的时候,比如调用query_log_lzj这个服务,代码中能够正确加载对应的ObjectFactory,所以调用第一个服务时是没有问题的。但是调用第二个服务insert_log_lzj时,cxf使用的ObjectFactory代码依然是query_log_lzj服务的ObjectFactory内容,也就是说调用第二个服务的时候用错了ObjectFactory,这就造成了调用insert_log_lzj服务的方法时找不到对应的方法,因为query_log_lzj的ObjectFactory没有insert_log_lzj服务应有的方法,导致在后续的查找可调用方法时查找不到相应的方法,就报数组下标越界异常,导致服务调用失败(因为可以调用的方法会保存在一个方法数组里)。
知道这原因之后,原本以为是cxf的代码bug,可是通过查看源码,根本无从下手去修改,后来通过修改服务配置文件service.xml,把query_log_lzj、insert_log_lzj这两个服务的schemNamespace设置
成不一样,问题居然解决了。
个人感觉有可能是cxf内部的机制问题,或许是同样的约束空间不会重新加载ObjectFactory。
目前尚无法解释具体原因,只知道这样能解决该问题,如果有哪位大神遇到这种情况,知道具体原因,有更好的解决办法,希望能留言。