8.23Java远程方法中使用反射机制
java.lang.reflect
包
Construct
类获取构造方法信息
Method
类获取成员方法信息
Field
类获取成员变量信息
反射机制在网络编程中的应用
反射机制在网络编程中的应用,实现如何在客户端通过远程方法调用服务器端的方法。
步骤
写一个
HelloService
接口,该接口具有 getTime() 和 echo() 方法创建一个 HelloServiceImpl 类并实现 HelloService 接口
需求是:
-
客户端调用服务器端 Hello-ServiceImpl 类中的 getTime() 和 echo() 方法
实现方法:
客户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给服务器端。服务器端再调用相关对象的方法,然后把方法的返回值发送给客户端。
写一个Call类去实现:
package PracticeReview.RemoteCall;
/**
* Call类,实现反射的远程通信
* @since JDK 1.8
* @date 2021/08/23
* @author Lucifer
*/
public class Call {
private static final long serialVersionUID = 6659953547331194808L;
/*类名或者接口名*/
private String className;
/*方法名*/
private String methodName;
/*方法参数类型*/
private Class[] paramType;
/*方法参数值*/
private Object[] params;
// 表示方法的执行结果
// 如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。
private Object result;
public Call() {
}
public Call(String className, String methodName, Class[] paramType, Object[] params) {
this.className = className;
this.methodName = methodName;
this.paramType = paramType;
this.params = params;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getClassName() {
return className;
}
public String getMethodName() {
return methodName;
}
public Class[] getParamType() {
return paramType;
}
public Object[] getParams() {
return params;
}
public Object getResult() {
return result;
}
public void setClassName(String className) {
this.className = className;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public void setParamType(Class[] paramType) {
this.paramType = paramType;
}
public void setParams(Object[] params) {
this.params = params;
}
public void setResult(Object result) {
this.result = result;
}
public String toString() {
return "className=" + className + "methodName=" + methodName;
}
}
客户端为SimpleClient
,服务端为SimpleServer
。SimpleClient
调用SimpleServer
的HelloServicelmpl
的echo()
方法:
-
SimpleClient 创建一个 Call 对象,它包含调用 HelloService 接口的 echo() 方法的信息。
-
SimpleClient 通过对象输出流把 Call 对象发送给 SimpleServer。
-
SimpleServer 通过对象输入流读取 Call 对象,运用反射机制调用 HelloServiceImpl 对象的 echo() 方法,把 echo() 方法的执行结果保存到 Call 对象中。
-
SimpleServer 通过对象输出流把包含方法执行结果的 Call 对象发送给 SimpleClient。
-
SimpleClient 通过对象输入流读取 Call 对象,从中获得方法执行结果。
package PracticeReview.RemoteCall;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端实现类
* @since JDK 1.8
* @date 2021/08/23
* @author Lucifer
*/
public class SimpleClient {
public void invoke() throws Exception {
Socket socket = new Socket("localhost", 8000);
OutputStream out = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
InputStream in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
// 创建一个远程调用对象
Call call = new Call("ch12.HelloService", "echo", new Class[] { String.class }, new Object[] { "Java" });
oos.writeObject(call); // 向服务器发送Call对象
call = (Call) ois.readObject(); // 接收包含了方法执行结果的Call对象
System.out.println(call.getResult());
ois.close();
oos.close();
socket.close();
}
}
服务端代码:
package PracticeReview.RemoteCall;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* 服务端接收信息
* @since JDK 1.8
* @date 2021/08/23
* @author Lucifer
*/
public class SimpleServer {
private Map remoteObjects = new HashMap(); // 存放远程对象的缓存
/** 把一个远程对象放到缓存中 */
public void register(String className, Object remoteObject) {
remoteObjects.put(className, remoteObject);
}
public void service() throws Exception {
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("服务器启动.");
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(); // 接收客户发送的Call对象
System.out.println(call);
call = invoke(call); // 调用相关对象的方法
oos.writeObject(call); // 向客户发送包含了执行结果的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[] paramTypes = call.getParamType();
Method method = classType.getMethod(methodName, paramTypes);
Object remoteObject = remoteObjects.get(className); // 从缓存中取出相关的远程对象
if (remoteObject == null) {
throw new Exception(className + "的远程对象不存在");
} 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 server = new SimpleServer();
// 把事先创建的HelloServiceImpl对象加入到服务器的缓存中
server.register("ch13.HelloService", new HelloServiceImpl());
server.service();
}
}