竹笋

首页 » 问答 » 环境 » 面试官不讲码德,欺负我一个年轻的开发工程
TUhjnbcbe - 2023/10/31 17:10:00
中医治白癜风 https://jbk.familydoctor.com.cn/bjbdfyy_ks4606/

面试官不讲码德,欺负我一个年轻的开发工程师,问如果是你怎么设计RPC?

RPC也不是很难啊,教你如何使用socket加动态代理与反射实现Rpc

先来解释解释一下rpc,首先很多人以为rpc是一种协议,其实这个就是出错误的,rpc:是远程过程调用;

看他的全程英文RemotePositionControl他其实是一种设计思想而已,解决分布式各个系统之间的调用关系。

我们今天就用socket方式实现一套rpc调用框架,不多说上代码

Java从入门到项目实战java语言编程入门书零基础自学教程淘宝¥49.8¥79.8购买

packagerpc.socket;

//先定义一个clinet接口

publicinterfaceClinetT{

TgetService(ClassTtClass);

}

这是我个人写的一个实现类,给位大牛可以尝试实现

这里是采用动态代理。把调用大的过程交给代理对象,这样就可以屏蔽掉底层的网络和整个调用过程,

对于客服而言只用给一个接口的class对象,他会帮你去找到服务端实现类,实现远程调用

importjava.io.*;

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

importjava.net.Socket;

importjava.util.Properties;

publicclassRpcClintimplementsClinet{

finalstaticStringRPC_SERVER_HOST=RPC_SERVER_HOST;

finalstaticStringRPC_SERVER_PORT=RPC_SERVER_PORT;

Override

publicObjectgetService(ClassaClass){

returnProxy.newProxyInstance(aClass.getClassLoader(),newClass[]{aClass},newInvocationHandler(){

Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{

//读取配置文件

Propertiesproperties=newProperties();

InputStreamresourceAsStream=aClass.getClassLoader().getResourceAsStream(rpc/RpcConfig.properties);

properties.load(resourceAsStream);

Stringhost=properties.getProperty(RPC_SERVER_HOST);

Integerport=newInteger((String)properties.get(RPC_SERVER_PORT));

//RPC注册过程

Socketsocket=newSocket(host,port);

OutputStreamin=socket.getOutputStream();

ObjectOutputStreamobjectOutputStream=newObjectOutputStream(in);

//告诉服务端调用的是哪个类

objectOutputStream.writeObject(aClass.getName());

//告诉服务端调用的是哪个方法

objectOutputStream.writeObject(method.getName());

//告诉服务端调用方法传入的参数

objectOutputStream.writeObject(args);

//告诉服务端调用方法的参数类型

objectOutputStream.writeObject(method.getParameterTypes());

//完成序列化,刷新

objectOutputStream.flush();

//接受服务端响应结果

ObjectInputStreamreturnObj=newObjectInputStream(socket.getInputStream());

Objecto=returnObj.readObject();

//关闭流

objectOutputStream.close();

returnObj.close();

resourceAsStream.close();

socket.close();

returno;

}

});

}

这是服务端接口

importjava.io.IOException;

publicinterfaceServer{

voidHandler()throwsIOException;

这是我实现的服务端rpc,就是采用一个nio接受客服端数据,然后去调用服务端的方法

importrpc.socket.service.GODService;

importrpc.socket.service.GODServiceImpl;

importjava.io.ObjectInputStream;

importjava.io.ObjectOutputStream;

importjava.lang.reflect.Constructor;

importjava.lang.reflect.InvocationTargetException;

importjava.net.ServerSocket;

importjava.util.Map;

importjava.util.concurrent.ConcurrentHashMap;

importjava.util.concurrent.ConcurrentMap;

publicclassRpcServerimplementsServer{

//装用实现类的bena

staticMapString,ClassRESmap;

//加载所有需要注册的额服务

static{

//这里可以用Aop加注解的方式来把需要暴露的服务,注册到服务列表里面去

RESmap=newConcurrentHashMap();

//把服务注册到注册表

RESmap.put(GODService.class.getName(),GODServiceImpl.class);

publicvoidHandler()throwsIOException{

ServerSocketserverSocket=newServerSocket();

//采取传统的bio处理

while(true){

//等待客服端链接

Socketaccept=serverSocket.accept();

newThread(()-{

try{

//等待客户端输入

ObjectInputStreamin=newObjectInputStream(accept.getInputStream());

//获取客户端传过来的类名称

StringclassName=(String)in.readObject();

//获取客户端客服端传过来的方法名称

StringmethodName=(String)in.readObject();

//获取客户端传过来的参数

Object[]args=(Object[])in.readObject();

//获取客服的端传过来的参数类型

Class[]argsType=(Class[])in.readObject();

//从注册表中获取服务的字节码

ClassaClass=RESmap.get(className);

//通过字节码对象获取构造器

Constructorconstructor=aClass.getConstructor();

constructor.setAccessible(true);

//通过反射的方式创建对象并且执行对象的方法

Objectinvoke=aClass.getMethod(methodName,argsType).invoke(constructor.newInstance(),args);

//把返回结果写回给客户端

ObjectOutputStreamreturnObject=newObjectOutputStream(accept.getOutputStream());

returnObject.writeObject(invoke);

//关闭流

in.close();

returnObject.close();

accept.close();

}catch(IOExceptione){

e.printStackTrace();

}catch(ClassNotFoundExceptione){

}catch(IllegalAccessExceptione){

}catch(InstantiationExceptione){

}catch(NoSuchMethodExceptione){

}catch(InvocationTargetExceptione){

}

}).start();

}

这里我们来建立一个服务端

首先定义一个接口

packagerpc.socket.service;

publicinterfaceGODService{

StringgetGod(StringlockMessage,Stringofferings);

实现类

publicclassGODServiceImplimplementsGODService{

publicStringgetGod(StringlockMessage,Stringofferings){

System.out.println(的供品:+offerings);

System.out.println(你的愿望:+lockMessage);

return年轻人还是少做梦!;

写一个服务端的启动类

packagerpc.socket.demo;

importrpc.socket.RpcServer;

publicclassServiceStart{

publicstaticvoidmain(String[]args)throwsIOException{

newRpcServer().Handler();

然后是客服端去调用

importrpc.socket.Clinet;

importrpc.socket.RpcClint;

publicclassclintDemo{

publicstaticvoidmain(String[]args){

ClinetClint=newRpcClint();

GODServiceservice=(GODService)Clint.getService(GODService.class);

StringlockReturn=service.getGod(请给让我中彩票吧,献祭我老板的二十年寿命!);

System.out.println(lockReturn);

我们来看两遍的结果

客服端结果

我来看服务端结果

很显然调用成功了

现在我们来画图模拟一下调用过程

1
查看完整版本: 面试官不讲码德,欺负我一个年轻的开发工程