[b][size=x-large]同步调用[/size][/b]
Hprose客户端在与服务器通讯时,分同步调用和异步调用两种方式。同步调用的概念和用法相对简单一些,所有我们先来介绍同步调用方式。
在同步调用方式下,如果服务器执行出错,或者通讯过程中出现问题(例如连接中断,或者调用的服务器不存在等),则客户端会抛出异常。
直接使用HproseHttpClient上的invoke方法或者采用代理接口方式都可以进行同步调用,但是只有通过invoke方法才能进行引用参数传递。
在下面的例子中,我们以调用前一章中第一节第一小节最后发布的服务为例来进行说明讲解。
[b][size=large]通过invoke方法进行同步调用[/size][/b]
通过invoke方法调用是最直接、最基本的方式,所以我们先来介绍它。
[b]带名称空间(别名前缀)方法[/b]
先来看调用最简单的例子:
package hprose.exam;
import hprose.client.HproseHttpClient;
import java.io.IOException;
public class ClientExam1 {
public static void main(String[] args) throws IOException {
HproseHttpClient client = new HproseHttpClient();
client.useService("http://localhost:8084/HproseExamServer/Methods");
System.out.println(client.invoke("ex1_getId"));
System.out.println(client.invoke("ex2_getId"));
}
}
这个例子调用的是服务器端发布的getId方法,因为我们在发布时发布了Exam1和Exam2两个类的对象上的这个方法,并且分别指定了名称空间(别名前缀),所以这里调用时,我们分别都加了ex1和ex2这两个前缀,并且用下划线“_”分隔别名前缀和方法名。这个例子的运行结果是:
[quote]Exam1
Exam2[/quote]
从结果中我们可以很清楚的分辨出它们确实是调用了两个不同类的对象的方法。
[b]可变的参数和结果类型[/b]
下面我们再来看对sum方法的调用:
package hprose.exam;
import hprose.client.HproseHttpClient;
import java.io.IOException;
import java.util.ArrayList;
public class ClientExam2 {
public static void main(String[] args) throws IOException {
HproseHttpClient client = new HproseHttpClient();
client.useService("http://localhost:8084/HproseExamServer/Methods");
System.out.println(client.invoke("ex1_sum", new Object[] { new int[] {1,2,3,4,5} }));
System.out.println(client.invoke("ex1_sum", new Object[] { new short[] {6,7,8,9,10} }));
System.out.println(client.invoke("ex1_sum", new Object[] { new long[] {11,12,13,14,15} }));
System.out.println(client.invoke("ex1_sum", new Object[] { new double[] {16,17,18,19,20} }));
System.out.println(client.invoke("ex1_sum", new Object[] { new String[]
{"21","22","23","24","25"} }));
ArrayList intList = new ArrayList();
intList.add(26);
intList.add(27);
intList.add(28);
intList.add(29);
intList.add(30);
System.out.println(client.invoke("ex2_sum", new Object[] { intList },
double.class));
}
}
因为,sum也是有别名的,所以调用时要加ex1或ex2的前缀,虽然这两个方法对应服务器上不同对象上的两个方法,但是这两个方法作用是一致的,所以不管调用哪个,结果都是一致的。
下面看运行结果:
[quote]15
40
65
90
115
140.0[/quote]
大家还会发现,sum在服务器端声明时,参数为int[]类型,结果为int类型,但是在调用时,我们除了可以带入int[]类型的参数外,还可以带入short[]、long[],甚至是double[]、String[]等类型的数组和List对象(如上例中的ArrayList),只要它们元素的值能够转换为int就可以。
sum的结果默认以Integer类型返回,但是您也可以指定其它类型作为返回值类型,只要该类型是反序列化有效类型即可。例如上例中,最后一个调用ex2_sum的例子,我们指定了double类型为返回值类型,所以得到的结果是140.0。
[b]引用参数传递[/b]
下面我们来继续看对swapKeyAndValue方法的调用:
package hprose.exam;
import hprose.client.HproseHttpClient;
import java.io.IOException;
import java.util.HashMap;
public class ClientExam3 {
public static void main(String[] args) throws IOException {
HproseHttpClient client = new HproseHttpClient();
client.useService("http://localhost:8084/HproseExamServer/Methods");
HashMap map = new HashMap();
map.put("January", "Jan");
map.put("February", "Feb");
map.put("March", "Mar");
map.put("April", "Apr");
map.put("May", "May");
map.put("June", "Jun");
map.put("July", "Jul");
map.put("August", "Aug");
map.put("September", "Sep");
map.put("October", "Oct");
map.put("November", "Nov");
map.put("December", "Dec");
Object[] arguments = new Object[] { map };
HashMap result = (HashMap)client.invoke("ex1_swapKeyAndValue", arguments);
System.out.println(map);
System.out.println(result);
System.out.println(arguments[0]);
result = (HashMap)client.invoke("ex2_swapKeyAndValue", arguments, true);
System.out.println(map);
System.out.println(result);
System.out.println(arguments[0]);
}
}
运行结果:
[quote]{October=Oct, January=Jan, April=Apr, February=Feb, August=Aug, June=Jun, November=Nov, July=Jul, May=May, December=Dec, March=Mar, September=Sep}
{Sep=September, Feb=February, Mar=March, Apr=April, Oct=October, Jan=January, May=May, Nov=November, Dec=December, Jul=July, Aug=August, Jun=June}
{October=Oct, January=Jan, April=Apr, February=Feb, August=Aug, June=Jun, November=Nov, July=Jul, May=May, December=Dec, March=Mar, September=Sep}
{October=Oct, January=Jan, April=Apr, February=Feb, August=Aug, June=Jun, November=Nov, July=Jul, May=May, December=Dec, March=Mar, September=Sep}
{Sep=September, Feb=February, Mar=March, Apr=April, Oct=October, Jan=January, May=May, Nov=November, Dec=December, Jul=July, Aug=August, Jun=June}
{Sep=September, Feb=February, Mar=March, Apr=April, Oct=October, Jan=January, May=May, Nov=November, Dec=December, Jul=July, Aug=August, Jun=June}
[/quote]
从上面的调用演示了引用参数传递。在对ex1_swapKeyAndValue进行调用时,我们没有设置引用参数传递,所以运行后,返回的结果result中的key与value对调了,但是参数值map和arguments[0]并没有对调。但是在对ex2_swapKeyAndValue进行调用时,我们设置了引用参数传递,所以调用后,参数arguments[0]的值也发生了变化,但是需要注意的是,原始的map并没有改变,改变的是参数数组arguments当中的值。
[b]自定义类型的传输[/b]
最后我们来看一下对getUserList方法的调用:
package hprose.exam;
import hprose.client.HproseHttpClient;
import java.io.IOException;
import java.util.List;
public class ClientExam4 {
public static void main(String[] args) throws IOException {
HproseHttpClient client = new HproseHttpClient();
client.useService("http://localhost:8084/HproseExamServer/Methods");
List<User> userList = (List<User>)client.invoke("ex2_getUserList");
for (User user : userList) {
System.out.printf("name: %s, ", user.getName());
System.out.printf("age: %d, ", user.getAge());
System.out.printf("sex: %s, ", user.getSex());
System.out.printf("birthday: %s, ", user.getBirthday());
System.out.printf("married: %s.", user.isMarried());
System.out.println();
}
System.out.println();
User[] users = (User[])client.invoke("ex2_getUserList", User[].class);
for (User user : users) {
System.out.printf("name: %s, ", user.getName());
System.out.printf("age: %d, ", user.getAge());
System.out.printf("sex: %s, ", user.getSex());
System.out.printf("birthday: %s, ", user.getBirthday());
System.out.printf("married: %s.", user.isMarried());
System.out.println();
}
}
}
运行结果:
[quote]name: Amy, age: 26, sex: Female, birthday: 1983-12-03, married: true.
name: Bob, age: 20, sex: Male, birthday: 1989-06-12, married: false.
name: Chris, age: 29, sex: Unknown, birthday: 1980-03-08, married: true.
name: Alex, age: 17, sex: InterSex, birthday: 1992-06-14, married: false.
name: Amy, age: 26, sex: Female, birthday: 1983-12-03, married: true.
name: Bob, age: 20, sex: Male, birthday: 1989-06-12, married: false.
name: Chris, age: 29, sex: Unknown, birthday: 1980-03-08, married: true.
name: Alex, age: 17, sex: InterSex, birthday: 1992-06-14, married: false.
[/quote]
上例中,返回结果默认是ArrayList,所以我们用List接收结果没有问题,另外,为了后面for循环时不用手动转型,我们使用的是泛型的List,但是要注意,泛型中所标明的User类必须与服务器端的User类定义完全一致,包括名称空间(包名),否则在运行时会发生类型转换错误。
不过可以通过指定User数组类型作为返回结果,这种情况下,客户端的User类可以与服务器的User类名空间不同(甚至类名不同也可以),只需要其内部序列化的字段和属性相同就可以啦。通常,如果在不需要对返回的结果作增删的时候,指定数组类型作为返回结果更高效和方便一些。