背景:项目需求要求与一个外部接口做对接,对方的服务端是cxf,而项目组用的是xfire1.2.6,JDK1.5。
对方也不可能改他们的服务端为xfire版本。
问题:因为历史原因,本项目是运行了多年的老系统,jdk1.5的环境,客户不可能因为一个接口就升级jdk到1.6,而且老系统里有很多接口都是在xfire上开发的,也不可能因为cxf来一次大改动,还不包括测试。
执行:用xfire静态模式来调用cxf服务端,报错,有注解的错,jar兼容的问题,还有一些网上讨论的问题。花了一周时间做了各自修改测试(配置上的),都无法完美解决xfire客户端调用cxf服务端的问题。
其中甚至包括把cxf生成的对应客户端包括环境jar包打成一个jar包来测试(目的是不影响生产环境其他jar,可以不用为升级jar或兼容问题操心了),
但是测试发现,这种打jar包的方法只能在jdk1.6下执行,在jdk1.5下就报找不到rt.jar下的
java.lang.NoClassDefFoundError: javax/xml/ws/Service
初衷是想不伤筋动骨下完成这个接口的对接。
看来不做点小手术是不行的了,好吧,开始改xfire源码。
cxf就是在xfire基础上升级而来的,cxf解决了xfire的很多缺陷,并且xfire停留在1.2.6版本上就再没更新了。
大趋势是cxf替换掉老掉牙的xfire,但你那注解式的开发貌似引出配置上很多问题,而且本人极度不习惯注解;而且cxf对soap是严格标准,对xfire很难容忍,xfire的一些元素命名格式不符合cxf的标准,导致xfire client to cxf无法成功。
那么开始从soap入手看看到底哪里不对了。
设置cxf服务端接口,支持打印请求和响应:
这个是我测试的接口文件和接口方法
@WebService
@Features(features = "org.apache.cxf.feature.LoggingFeature")
public interface HelloWord {
public @WebResult String sayHello(String name,String agr);
}
先来看cxf客户端调用的soap请求和服务端的响应:
2013-1-23 13:07:17 org.apache.cxf.interceptor.LoggingInInterceptor logging
信息: Inbound Message
----------------------------
Encoding: UTF-8
Headers: {content-length=[198], connection=[keep-alive], cache-control=[no-cache
], host=[localhost:8083], user-agent=[Java/1.5.0_12], SOAPAction=[""], pragma=[n
o-cache], content-type=[text/xml; charset=UTF-8], Accept=[*]}
Messages:
Message:
Payload: http://schemas.xmlsoap.org/soap/envelope/"><<BR>soap:Body>doony28http://test.com/">doony28
rg1>
--------------------------------------
say hello age=28
2013-1-23 13:07:17 org.apache.cxf.interceptor.LoggingOutInterceptor$LoggingCallb
ack onClose
信息: Outbound Message
---------------------------
Encoding: UTF-8
Headers: {}
Messages:
Payload: http://schemas.xmlsoap.org/soap/envelope/"><<BR>soap:Body>hello">http://test.com/">hello doony age 28
--------------------------------------
再来看xfire的请求:
Payload: http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
xmlns:xsi="
">http://www.w3.org/2001/XMLSchema-instance">
/">http://test.com">
doony
28
可以看到xfire对sayHello的参数,包了个“”的标签。
以及的也少了一个“/”,
那么是否能把soap改成和cxf一致就可以了呢。
一番调试,确定了soap生成的java类是“org.codehaus.xfire.service.binding.AbstractBinding”。
修改它,让它支持cxf,再测,
yes,xfire可以了。
题外话,调试过程中,发现xfire确实存在不少优化及待改进的问题 ,下来有时间慢慢完善,
不想这么快就杀死xfire,系统还是存在很多外部调用方也是xfire的,我们升级成cxf,那估计他们要痛苦了。
这里附上xfire的动态客户端代码,方便测试:
import java.net.HttpURLConnection;
import java.net.URL;
import org.codehaus.xfire.client.Client;
import org.codehaus.xfire.transport.http.CommonsHttpMessageSender;
public class Test {
public static final String WebService_URL = "http://localhost:8083/WebService/HelloWorld?wsdl";
public static void main(String[] args) {
Client client1 = null;
try {
URL _url = new URL(WebService_URL);
HttpURLConnection httpConnection = (HttpURLConnection)_url.openConnection();
httpConnection.setReadTimeout(20000);//设置http连接的读超时,单位是毫秒
httpConnection.connect();
client1 = new Client(httpConnection.getInputStream(), null);
client1.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT, String.valueOf( 20000 ));//设置发送的超时限制,单位是毫秒;
client1.setProperty(CommonsHttpMessageSender.DISABLE_KEEP_ALIVE, "true");
client1.setProperty(CommonsHttpMessageSender.DISABLE_EXPECT_CONTINUE, "true");
Object[] strResult1 = null;
// 如果接口有方法名,且需要带参数,则在 invoke注明,参数以Object[]数组形式
strResult1 = client1.invoke("sayHello", new Object[] {"doony","28"});
System.out.println("调接口返回xml格式-->" + strResult1[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
}