(远程方法的调用)对象序列化反射在网络编程的运用
Posted lazyli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(远程方法的调用)对象序列化反射在网络编程的运用相关的知识,希望对你有一定的参考价值。
对象的序列化与反序列化【p213页】
当两个进程进行远程通信时,彼此可以发送各种类型的数据,如文本、图
片、语音和视频等。无论不纯二进制序列的形式在网络上传送。当两个
java进程进行远程通信时,一个进程把一个java对象发送到另一个进程
中。不过发送方需要把这个java对象转换为字节序列,才能在网络上传
送;接收方则需要把自己序列在恢复为java对象。把java对象转换为字
节序列的过程称为对象序列化;把字节序列恢复为java对象的过程称为
对象称为对象的反序列化。
JDK类库中的序列化API
java.io.ObjectOutputStream代表对象的输出流,它的writeObject
(Object obj)方法将对象进行序列化输出。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法
从一个源输入流读取字节序列,在将字节序列转换为一个java对象。
只有实现了Serializable或Externalizable接口的类的对象才能被序列
化。JDK类库中部分类(String类,包装类和Date类等)都实现了
Serializable接口。
当属性值被transient修饰,该属性是不会被序列化和反序列的
对序列化进行加密处理,[p224]
一个类如果实现了Externalizable接口,那么它必须具有public类型的
不带参数的构造方法,否则这个类无法反序列化。
------------
java Reflection API(java 反射机制)
主要功能:
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法;
4、在运行时任意调用一个对象的方法;
5、生成动态代理。
public class ReflectDemo01 {
public static void main(String[] args) throws
ClassNotFoundException {
Class classzz = A.class;
System.out.println(classzz);
Method[] methods = classzz.getMethods();
for(Method method : methods){
System.out.println(method.toString
());
}
}
}
class A{
public void say(){
}
}
在远程方法中运用反射机制
客户端调用服务端的方法:Simple客户端如何调用服务端的
public interface HelloService {
public String echo(String msg);
public Date getTime();
}
public class HelloServiceImpl implements HelloService {
@Override
public String echo(String msg) {
return "echo" + msg;
}
@Override
public Date getTime() {
// TODO Auto-generated method stub
return new Date();
}
}
HelloServiceImpl对象的getTime()和echo()方法。SimpleClient客
户端需要把调用的方法名、方法参数类型、方法参数值,以及方法所属的
类名或接口发送给SimpleServer,SimpleServer再调用相关对象的方法
,然后把方法的返回值发送给SimpleClient。
用Call类封装相关信息,它包括调用的类名或接口名、方法名、方法参
数类型、方法参数值和方法执行结果。
public class Call implements Serializable{
private String className;//表示类名或接口
private String methodName;//表示方法名
private Class[] paramTypes; //表示方法参数类型
private Object[] params; //表示方法参数值
//表示方法执行结果
//如果方法正常执行,result为方法返回值,如果方法抛出异
常,那么result为异常
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;
}
public String toString(){
return "className="+className+"
methodName="+methodName;
}
}
SimpleClient调用SimpleServer端的HelloServerImpl对象echo()方法
流程:
1、SimpleClient创建一个Call对象,它包含了调用HelloService接口
的echo()方法的信息。
2、SimpleClient通过对象输出流把Call对象发送给SimpleServer。
3、SimpleServer通过对象输入流读取Call对象,运用反射机制调用
HelloServiceImpl对象的echo()方法,把echo()方法的执行结果保存到
Call对象中。
4、SimpleServer通过对象输出流把包含了方法执行结果的Call对象发送
给SimpleClient。
5、SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果
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(8088);
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.getParamTypes();
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对象加入到服务器
的缓存中,
//"com.lazy.socket.reflect.HelloService"类的
全限定名
server.register
("com.lazy.socket.reflect.HelloService", new
HelloServiceImpl());
server.service();
}
}
客户端
public class SimpleClient {
public void invoke() throws Exception{
Socket socket = new Socket("localhost",
8088);//连接服务端
OutputStream out = socket.getOutputStream();
ObjectOutputStream oos = new
ObjectOutputStream(out);
InputStream in = socket.getInputStream();
ObjectInputStream ois = new
ObjectInputStream(in);
Call call = new Call
("com.lazy.socket.reflect.HelloService",
"getTime",new Class[]
{String.class},new Object[]{"hello"});
oos.writeObject(call);//向服务端发送call对象
call = (Call)ois.readObject();//接收包含了方
法执行结果的Call对象
System.out.println(call.getResult()+"---");
System.out.println(call.toString());
ois.close();
oos.close();
socket.close();
}
public static void main(String[] args) throws
Exception {
new SimpleClient().invoke();
}
}
注:Dubbo是调用服务端方法的。
以上是关于(远程方法的调用)对象序列化反射在网络编程的运用的主要内容,如果未能解决你的问题,请参考以下文章