CXF(使用版本2.7.6)对Web服务封装度已经非常高了,你只需要像正常写代码一样,附加几个额外的注解直接发布,服务端差不多就完成了;对于客户端更简单,只需要知道Web服务的URL地址和接口,就能如调用本地代码一样,几乎感觉不到与本地代码有什么区别。这就是封装的威力,虽然高度封装简化了我们对Web服务的使用,但也间接地阻挡了我们对其深入了解。本文就将源码层面来分析CXF其内部是如何完成客户端对Web服务的调用封装的,但并不包含服务端对服务请求的处理过程,如有需要可参看上篇,CXF中Web服务请求处理流程。
最重要的当然是factoryBean.create()方法了,从代码表面上看,只知道其返回了一个实现了HelloService接口类实例,但它具体到底是什么呢?这当然就得去看看源码了:
因为调用处理器为ClientProxy,则客户端所有的Web服务调用都是调用ClientProxy的invoke方法,Web服务返回值就是invoke方法返回值,如下:
通过create()方法,可以知道在创建ClientProxy时传入了Client对象,而在invokeSync(method, oi, params);中主要就是调用了Client的invoke方法,其invoke方法经过多个重的invoke方法调用,最后调用的是doInvoke()方法:
以SOAP协议服务为例,当我们使用代码调用Web服务时,一般情况如下:
JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
String address = "...";//Web服务发布地址
factoryBean.setAddress(address);
factoryBean.setServiceClass(HelloService.class);//Web服务接口
HelloService helloService = factoryBean.create(HelloService.class);
helloService.sayHello("xtayfjpk");
最重要的当然是factoryBean.create()方法了,从代码表面上看,只知道其返回了一个实现了HelloService接口类实例,但它具体到底是什么呢?这当然就得去看看源码了:
public <ProxyServiceType> ProxyServiceType create(Class<ProxyServiceType> serviceClass) {
setServiceClass(serviceClass);
//看上去很简单啊,别急,操作都是create()方法中呢
return serviceClass.cast(create());
}
public synchronized Object create() {
ClassLoaderHolder orig = null;
try {
if (getBus() != null) {
ClassLoader loader = getBus().getExtension(ClassLoader.class);
if (loader != null) {
orig = ClassLoaderUtils.setThreadContextClassloader(loader);
}
}
//配置this,即JaxWsProxyFactoryBean对象
configureObject();
if (properties == null) {
properties = new HashMap<String, Object>();
}
if (username != null) {
AuthorizationPolicy authPolicy = new AuthorizationPolicy();
authPolicy.setUserName(username);
authPolicy.setPassword(password);
properties.put(AuthorizationPolicy.class.getName(), authPolicy);
}
//为clientFactoryBean与ServiceFactory设置features
initFeatures();
clientFactoryBean.setProperties(properties);
if (bus != null) {
clientFactoryBean.setBus(bus);
}
if (dataBinding != null) {
clientFactoryBean.setDataBinding(dataBinding);
}
//由工厂类创建出Client对象,实现类为ClientImpl,并且创建出了Endpoint、Service对象
Client c = clientFactoryBean.create();
//将各种拦截器设置进Client中
if (getInInterceptors() != null) {
c.getInInterceptors().addAll(getInInterceptors());
}
if (getOutInterceptors() != null) {
c.getOutInterceptors().addAll(getOutInterceptors());
}
if (getInFaultInterceptors() != null) {
c.getInFaultInterceptors().addAll(getInFaultInterceptors());
}
if (getOutFaultInterceptors() != null) {
c.getOutFaultInterceptors().addAll(getOutFaultInterceptors());
}
//创建客户端代理对象
ClientProxy handler = clientClientProxy(c);
//获取代理需要实现的接口,包含Web服务接口与java.io.Closeable
Class<?> classes[] = getImplementingClasses();
//这里是最关键代码,使用JDK提供的Proxy类创建出一个代理对象,该代理对象实现了Web服务接口与java.io.Closeable接口
//而调用处理器(InvocationHandler)对象就是刚创建的ClientProxy对象
Object obj = Proxy.newProxyInstance(clientFactoryBean.getServiceClass().getClassLoader(),
classes,
handler);
this.getServiceFactory().sendEvent(FactoryBeanListener.Event.PROXY_CREATED,
classes, handler, obj);
return obj;
} finally {
if (orig != null) {
orig.reset();
}
}
}
因为调用处理器为ClientProxy,则客户端所有的Web服务调用都是调用ClientProxy的invoke方法,Web服务返回值就是invoke方法返回值,如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//省略...
MethodDispatcher dispatcher = (MethodDispatcher)endpoint.getService().get(MethodDispatcher.class
.getName());
BindingOperationInfo oi = dispatcher.getBindingOperation(method, endpoint);
//省略...
Object[] params = args;
if (null == params) {
params = new Object[0];
}
//进行同步调用
Object o = invokeSync(method, oi, params);
//call a virtual method passing the object. This causes the IBM JDK
//to keep the "this" pointer references and thus "this" doesn't get
//finalized in the midst of an invoke operation
return adjustObject(o);
}
通过create()方法,可以知道在创建ClientProxy时传入了Client对象,而在invokeSync(method, oi, params);中主要就是调用了Client的invoke方法,其invoke方法经过多个重的invoke方法调用,最后调用的是doInvoke()方法:
private Object[] doInvoke(ClientCallback callback,