本文共 4892 字,大约阅读时间需要 16 分钟。
在前面几篇文章中都是使用同步方式来调用 WebService 。也就是说,如果被调用的 WebService 方法长时间不返回,客户端将一直被阻塞,直到该方法返回为止。使用同步方法来调用 WebService 虽然很直观,但当 WebService 方法由于各种原因需要很长时间才能返回的话,就会使客户端程序一直处于等待状态,这样用户是无法忍受的。 当然,我们很容易就可以想到解决问题的方法,这就是多线程。解决问题的基本方法是将访问 WebService 的任务交由一个或多个线程来完成,而主线程并不负责访问 WebService 。这样即使被访问的 WebService 方法长时间不返回,客户端仍然可以做其他的工作。我们可以管这种通过多线程访问 WebService 的方式称为异步访问。 虽然直接使用多线程可以很好地解决这个问题,但比较麻烦。幸好 Axis2 的客户端提供了异步访问 WebService 的功能。 RPCServiceClient 类提供了一个 invokeNonBlocking 方法可以通过异步的方式来访问 WebService 。下面先来建立一个 WebService 。 MyService 是一个 WebService 类,代码如下:
package service; public class MyService { public String getName() { try { System.out.println( " getName方法正在执行 " ); // 延迟5秒 Thread.sleep( 5000 ); } catch (Exception e) { } return " 火星 " ; } } 为了模拟需要一定时间才返回的WebService
方法,在getName
方法中使用了sleep
方法来延迟5
秒。 下面是MyService
类的配置代码:
<!-- services.xml --> < service name ="myService" > < description > 异步调用演示 </ description > < parameter name ="ServiceClass" > service.MyService </ parameter > < messageReceivers > < messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </ messageReceivers > </ service > 从上面的配置代码可以看出,MyService
的配置方式与前几章的WebService
的配置方式完全一样,也就是说,MyService
只是一个普通的WebService
。 下面是异步调用MyService
的Java
客户端代码:
package client; import javax.xml.namespace.QName; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.context.MessageContext; import org.apache.axis2.rpc.client.RPCServiceClient; public class RPCAsyncClient { public static void main(String[] args) throws Exception { RPCServiceClient serviceClient = new RPCServiceClient(); Options options = serviceClient.getOptions(); EndpointReference targetEPR = new EndpointReference( " http://localhost:8080/axis2/services/myService " ); options.setTo(targetEPR); Object[] opAddEntryArgs = new Object[]{}; QName opAddEntry = new QName( " http://service " , " getName " ); serviceClient.invokeNonBlocking(opAddEntry, opAddEntryArgs, new org.apache.axis2.client.async.AxisCallback() { @Override public void onComplete() { } @Override public void onError(Exception arg0) { } } @Override public void onFault(MessageContext arg0) { } @Override public void onMessage(MessageContext mc) { // 输出返回值 System.out.println(mc.getEnvelope().getFirstElement() .getFirstElement().getFirstElement().getText()); } }); System.out.println( " 异步调用! " ); // 阻止程序退出 System.in.read(); } } 从上面的代码可以看出,invokeNonBlocking
方法有三个参数,前两个参数分别指定了要调用的方法及方法参数的相关信息,而最后一个参数并不是方法返回值的类型信息,而是一个实现org.apache.axis2.client.async.AxisCallback
接口的类的对象实例。在本例中隐式实现了AxisCallback
接口。在AxisCallback
接口中有四个方法需要实现,其中当被异步调用的方法返回时onMessage
方法被调用。当运行上面的程序后,将输出如下的信息: 虽然上面的例子可以实现异步调用,但比较麻烦。为了更方便地实现异步调用,可以使用wsdl2java
命令的-a
参数生成可异步调用的Stub
类。下面的命令可生成同步和异步调用的客户端代码(两个类),其中-s
表示生成同步调用代码,-a
表示生成异步调用代码。 %AXIS2_HOME%\bin\wsdl2java -uri http://localhost: 8080 /axis2/services/myService?wsdl -p client -s -a -o stub 在执行上面的命令后,将生成两个类:MyServiceStub
和MyServiceCallbackHandler
类,其中MyServiceStub
类负责同步和异步调用WebService
,MyServiceCallbackHandler
类是一个抽象类,也是一个回调类,当使用异步方式调用WebService
方法时,如果方法返回,则MyServiceCallbackHandler
类的receiveResultgetName
方法被调用。下面是使用MyServiceStub
类异步访问WebService
的代码: package client; import client.MyServiceStub.GetNameResponse; class MyCallback extends MyServiceCallbackHandler { @Override public void receiveResultgetName(GetNameResponse result) { // 输出getName方法的返回结果 System.out.println(result.get_return()); } } public class StubClient { public static void main(String[] args) throws Exception { MyServiceStub stub = new MyServiceStub(); // 异步调用WebService stub.startgetName( new MyCallback()); System.out.println( " 异步调用! " ); System.in.read(); } }
在.net中也可以使用异步的方式来调用WebService,如在C#中可使用如下的代码来异步调用getName方法:
// 回调方法 private void getNameCompletedEvent(object sender, WSC.asyn.getNameCompletedEventArgs e) { listBox1.Items.Add( e.Result.@ return ); } private void button1_Click(object sender, EventArgs e) { async.myService my = new WSC.async.myService(); my.getNameCompleted += new WSC.async.getNameCompletedEventHandler(getNameCompletedEvent); my.getNameAsync(); MessageBox.Show( " 完成调用 " ); } 其中async
是引用MyService
的服务名。要注意的是,在C#
中不能在同一个WebService
实例的getName
方法未返回之前,再次调用该实例的getName
方法,否则将抛出异常。如下面的代码会抛出一个异常: async.myService my = new WSC.async.myService(); my.getNameCompleted += new WSC.async.getNameCompletedEventHandler(getNameCompletedEvent); my.getNameAsync(); // 将抛出异常 my.getNameAsync(); 但不同的WebService
实例的方法可以在方法未返回时调用,如下面的代码是可以正常工作的: asyn.myService my = new WSC.asyn.myService(); my.getNameAsync(); my.getNameCompleted += new WSC.asyn.getNameCompletedEventHandler(getNameCompletedEvent); asyn.myService my1 = new WSC.asyn.myService(); my1.getNameCompleted += new WSC.asyn.getNameCompletedEventHandler(getNameCompletedEvent); my1.getNameAsync(); 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/215187,如需转载请自行联系原作者