远程方法调用的模仿实现(附系统的通信图)
RMI 即remote method invoke
远程方法调用:基于一种网络的技术
在本地执行一个方法,实际上是在服务器端完成的 即服务器端真正的执行了这个方法 并且通过网络进行函数执行结果的返回给客户端
下面我们逐步分析;
1 首先我们进行 服务器与客户端的建立
2 并通过 ***来进行方法的执行
3 最终返回给客户端
这是我们进行分析之后,得到这个工程的通信图
RMI源码git链接
我们可以开始设计代码了
客户端
客户端代码进行服务器的连接,
并且将执行方法的 名字以及参数 传递给服务器端
最后准备接收服务器端传过来的函数结果
public class RMIClient1 {
private int RMIport;
private String RMIip;
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
//get 和set ip 以及port
public RMIClient1(int RMIport,String RMIip) {
this.RMIip=RMIip;
this.RMIport=RMIport;
}
void ConnectToServer() {
// 建立通信信道
try {
this.socket=new Socket(RMIip,RMIport);
this.dis=new DataInputStream(socket.getInputStream());
this.dos=new DataOutputStream(socket.getOutputStream());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public Object invokeMethod( Method method ,Object[] args) {
// 将要实现的方法传过去
ArgumentMaker argmaker=new ArgumentMaker();
for(int i=0;i<args.length;i++) {
argmaker.addArg("arg"+i, args[i]);
}
String argStr=argmaker.toString();
Object res=null;
try {
dos.writeUTF(String.valueOf(method.toString().hashCode()));
dos.writeUTF(argStr);
String result =dis.readUTF();
// 将由服务端返回的JSON字符串 结果传递回来给客户端
res=ArgumentMaker.gson.fromJson(result, method.getReturnType());
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
}
我们再来看看服务器端
他需要完成自己的启动 以及进行方法的执行
public class RMIServer1 implements Runnable{
private int port;
private ServerSocket server;
private volatile boolean goon;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public RMIServer1(int port) {
this.port=port;
}
void Startup() {
if(goon==true) {
return;
}
try {
server=new ServerSocket(port);
goon=true;
new Thread(this,"serverThread").start();
} catch (IOException e) {
e.printStackTrace();
}
}
void shutdown() {
if(goon==false) {
return ;
}
goon=false;
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
// 进行 服务器端的 通信线道的建立
// 进行 客户端传过来方法的执行
Socket socket;
try {
socket = server.accept();
new RMIActioner1(socket) ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里要遵循软件工程中职责单一的原则 故我们在RMIActioner里面进行方法的执行
在进行编写的过程中,突然发现invoke 函数执行的时候需要methodname 以及
Object 故定义了 MethodDefination类 给出两个成员的get和set方法
所以 利用工厂模式 将这他们生产出来
工厂里面有methodpool 键必须唯一 所以想到
利用method的名字 做hashmap得到唯一的键
private static Map<String ,RMIMethodDefination1 > methodPool;
// hashMap 的类型定义以及new一个hashmap的写法
static {
methodPool=new HashMap<>();
}
public void ScanPackage(String packagename) {
// 进行包扫描先得到有实现了有相应注解的接口
}
public void registryClass(Class<?> interfaces, Class<?> klass) {
// 注册 给methodPool里面填内容
if (interfaces == null || klass == null
|| !interfaces.isInterface() || klass.isInterface()
|| !interfaces.isAssignableFrom(klass)) {
// isAssignableFrom 判断是不是实现实现接口的类
return;
}
static RMIMethodDefination1 getMethod(String methodId) {
return methodPool.get(methodId);
}
}
进行方法的执行(参数以及方法的处理)
public RMIActioner1(Socket socket) {
try {
dis=new DataInputStream(socket.getInputStream());
dos=new DataOutputStream(socket.getOutputStream());
new Thread(this).start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
String methodname=dis.readUTF();
String arguments=dis.readUTF();
RMIMethodDefination1 methodDefination=RMIMethodFactory1.getMethod(methodname);
Object object=methodDefination.getObject();
Method method=methodDefination.getMethod();
Object values[] =getParameterValues(method, arguments);
try {
Object result=method.invoke(object, values);
dos.writeUTF(ArgumentMaker.gson.toJson(result));
//将执行结果传过去
close();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private Object[] getParameterValues(Method method ,String argsString) {
ArgumentMaker argumentMaker = new ArgumentMaker(argsString);
Parameter[] parameters = method.getParameters();
int ParameterCount=method.getParameterCount();
if(ParameterCount<=0){
return new Object[] {};
}
Object[] res=new Object[ParameterCount];
for(int i=0;i<ParameterCount;i++) {
String argname="arg"+i;
Object argvalue=argumentMaker.getValue(argname,
parameters[i].getParameterizedType());
res[i]=argvalue;
}
//得到了 参数的一个数组并且里面存着参数的值
return res;
}
最后因为要实现 方法利用***机制执行
故创建clientProxy类
public class RMIClientProxy1 {
private RMIClient1 client;
public RMIClientProxy1() {
}
public void setClient(RMIClient1 client) {
this.client = client;
}
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<?> klass) {
// loader, interfaces, h
return (T) Proxy.newProxyInstance(klass.getClassLoader(),
klass.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
client.ConnectToServer();
return client.invokeMethod(method, args);
}
}
);
}
}
这就是整个RMI的实现了!!!