公司项目中使用了分布式,采用的是猎聘网的一套框架,并未使用Dubbo,SpringCloud等流行的技术框架。在使用过程中,仅仅会常用的jar包升级、服务调用等,对具体的RPC实现原理没有真正的理解。这两天趁着周末不加班,学习了一下RPC的知识,实现了一个小的demo帮助理解。
分布式系统中,有下面几种角色:Consumer,Provider和注册中心。这里以前两种为重点介绍。在同一JVM中,类与类的调用关系通常为new出一个实例,然后调用实例方法。在分布式应用中,由于实体不存在于一个项目,类之间调用关系不能通过new来实现,因此需要通过代理类进行服务调用。
首先介绍服务端rpc-server端情况,服务端发布服务,对Consumer的调用进行处理并返回。
在服务端中存在一个接口IHgHello及其实现类HgHelloImpl,如下所示:
public interface IHgHello {
String sayHello(String name);
}
public class HgHelloImpl implements IHgHello {
@Override
public String sayHello(String name) {
return "这里是提供方,hello," + name;
}
}
服务端需要对IHgHello接口进行发布,让消费方进行调用。这里的类为RpcProxyServer,其主要负责接收客户端的socket连接并进行处理,具体的处理类为ProcessHandler。
public class RpcProxyServer {
ExecutorService executorService = Executors.newCachedThreadPool();
public void publisher(Object service,int port) throws IOException {
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(port);
while (true){
Socket socket= serverSocket.accept();
executorService.execute(new ProcessorHandler(service,socket));
}
}catch (IOException e){
e.printStackTrace();
}
}
}
public class ProcessorHandler implements Runnable {
Socket socket;
Object service;
public ProcessorHandler(Object service,Socket socket) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
System.out.println("begin process handler");
ObjectInputStream inputStream = null;
ObjectOutputStream outputStream = null;
try {
inputStream = new ObjectInputStream(socket.getInputStream());
RPCRequest request = (RPCRequest) inputStream.readObject();
Object result = invoke(request);
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.writeObject(result);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Object invoke(RPCRequest request) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object[] args = request.getParams();
Class<?>[] types = new Class[args.length];
for(int i=0;i<args.length;i++){
types[i] = args[i].getClass();
}
// 调用类
// request.getClassName();
Method method = service.getClass().getMethod(request.getMethodName(),types);
return method.invoke(service,args);
}
}
当Consumer连接上时,调用sayHello方法,服务端处理类ProcessorHandler通过反射获取调用的service类名、方法名和参数,通过原生的序列化和反序列化方法,进行结果返回。其中发布服务的方法为:
public static void main(String[] args) throws IOException {
IHgHello iHgHello = new HgHelloImpl();
RpcProxyServer rpcProxyServer = new RpcProxyServer();
rpcProxyServer.publisher(iHgHello,8080);
System.out.println(iHgHello.sayHello("haha,我是服务方"));
}
这样服务端的实现已经完成,下面进行客户端的实现。