在远程方法调用中也经常使用到java的反射机制,一下举个远程方法调用的例子,假定在SimpleServer 服务器端创建了一个HelloServiceImpl对象,它具有getTime()和echo()方法。HelloServiceImpl类实现了HelloService接口。如例下例所示分别是HelloService接口和HelloServiceImpl类的代码:
import java.util.Date; public interface HelloService { public String echo(String msg); public Date getTime(); }
import java.util.Date; public class HelloServiceImpl implements HelloService{ @Override public String echo(String msg) { // TODO Auto-generated method stub return "echo: "+ msg; } @Override public Date getTime() { // TODO Auto-generated method stub return new Date(); } }
SimpleClient客户端如何调用服务器端的HelloServiceImpl对象的getTime()和echo()方法呢?显然,SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给SimpleServer,SimpleServer 再调用相关对象的方法,然后把方法的返回值发送给SimpleClient。为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用Call 类来表示。一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。
import java.io.Serializable; import java.util.Arrays; public class Call implements Serializable { private String className; private String methodName; private Class[] paramTypes; private Object[] params; private Object result; public Call(){} public Call(String className, String methodName, Class[] paramTypes, Object[] params) { super(); this.className = className; this.methodName = methodName; this.paramTypes = paramTypes; this.params = params; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public Class[] getParamTypes() { return paramTypes; } public void setParamTypes(Class[] paramTypes) { this.paramTypes = paramTypes; } public Object[] getParams() { return params; } public void setParams(Object[] params) { this.params = params; } public Object getResult() { return result; } public void setResult(Object result) { this.result = result; } @Override public String toString() { return "Call [className=" + className + ", methodName=" + methodName+ "]"; } }
SimpleClient 调用SimpleServer 端的HelloServiceImpl 对象的echo()方法的流程如下:
(1)SimpleClient 创建一个Call 对象,它包含了调用HelloService 接口的echo()方法的信息。
(2)SimpleClient通过对象输出流把Call对象发送给SimpleServer。
(3)SimpleServer 通过对象输入流读取Call 对象,运用反射机制调用HelloServiceImpl对象的echo()方法,把echo()方法的执行结果保存到Call对象中。
(4)SimpleServer 通过对象输出流把包含了方法执行结果的Call 对象发送给SimpleClient。
(5)SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果。如下例所示分别是SimpleServer 和SimpleClient 的源程序。
import java.net.*; import java.util.*; import java.io.*; public class SimpleClient { public void invoke() throws Exception { Socket socket = new Socket("localhost", 8008); OutputStream out = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); InputStream in = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(in); Call call = new Call("t0428.HelloService", "echo", new Class[] { String.class }, new Object[] { "Hello" }); oos.writeObject(call); call = (Call) ois.readObject(); System.out.println(call.getResult()); ois.close(); oos.close(); socket.close(); } public static void main(String args[]) throws Exception { new SimpleClient().invoke(); } }
import java.lang.reflect.Method;
import java.net.*; import java.util.*; import java.io.*; public class SimpleServer { private Map remoteObjects = new HashMap(); public void register(String className, Object remoterObject) { remoteObjects.put(className, remoterObject); } public void service() throws Exception { ServerSocket serverSocket = new ServerSocket(8008); System.out.println("server is started"); while (true) { Socket socket = serverSocket.accept(); InputStream in = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(in); OutputStream out = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); Call call = (Call) ois.readObject(); System.out.println("server :"+ call); call = invoke(call); oos.writeObject(call); ois.close(); oos.close(); socket.close(); } } public Call invoke(Call call) { Object result = null; try { String className = call.getClassName(); String methodName = call.getMethodName(); Object[] params = call.getParams(); Class classType = Class.forName(className); Class[] paramTpyes = call.getParamTypes(); Method method = classType.getMethod(methodName, paramTpyes); Object remoteObject = remoteObjects.get(className); if(remoteObject == null){ throw new Exception(className + " the remote object is not existed!"); }else{ result = method.invoke(remoteObject, params); } } catch (Exception e) { result = e; } call.setResult(result); return call; } public static void main(String args[]) throws Exception{ SimpleServer ss = new SimpleServer(); ss.register("t0428.HelloService", new HelloServiceImpl()); ss.service(); } }