CXF客户端请求服务流程

CXF(使用版本2.7.6)对Web服务封装度已经非常高了,你只需要像正常写代码一样,附加几个额外的注解直接发布,服务端差不多就完成了;对于客户端更简单,只需要知道Web服务的URL地址和接口,就能如调用本地代码一样,几乎感觉不到与本地代码有什么区别。这就是封装的威力,虽然高度封装简化了我们对Web服务的使用,但也间接地阻挡了我们对其深入了解。本文就将源码层面来分析CXF其内部是如何完成客户端对Web服务的调用封装的,但并不包含服务端对服务请求的处理过程,如有需要可参看上篇,CXF中Web服务请求处理流程。

以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,
              
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot集成CXF时,可以使用CXF提供的工具类org.apache.cxf.jaxws.JaxWsProxyFactoryBean创建WebService客户,并使用该客户调用WebService接口方法。生成的SOAP请求包可以通过在客户代码中添加日志输出或使用抓包工具进行捕获。 以下是一个示例: 1. 定义WebService接口 ```java package com.example.demo; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; @WebService public interface HelloWorld { @WebMethod String sayHello(@WebParam(name = "name") String name); } ``` 2. 创建WebService客户 ```java package com.example.demo; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; public class HelloWorldClient { public static void main(String[] args) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(HelloWorld.class); factory.setAddress("http://localhost:8080/helloWorld"); HelloWorld helloWorld = (HelloWorld) factory.create(); String result = helloWorld.sayHello("World"); System.out.println(result); } } ``` 在以上代码中,通过JaxWsProxyFactoryBean创建了一个HelloWorld接口的代理对象,并指定了WebService的地址。调用sayHello方法后,将结果打印到控制台。 3. 查看SOAP请求包 可以通过在客户代码中添加日志输出或使用抓包工具进行捕获,例如使用Wireshark进行抓包,然后在过滤器中设置“http.request.method == POST && tcp.port == 8080”进行过滤,即可查看请求数据包。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值