一:什么是RPC
远程过程调用(Remote Procedure Call)。就是调用其他业务方的方法的时候,就像是调用自己本地的方法一样。
二:java rpc实现简介
服务端(使用反射)
(1)服务端写一个接口和一个接口的实现。
(2)服务端维护一个map,key为接口的类名,value为接口的实现类。
(3)服务端通过 ServerSocket 接收客户端发送过来的数据(接口的类名,方法名,请求参数)
(4)服务端根据接口的类名和方法名得到对应实现类的方法,通过反射调用服务
(5)把处理之后的结果通过 ServerSocket 返回给客户端
客户端(动态代理)
(1)把服务端的接口copy过来
(2)写一个代理类,调用服务端方法的时候,通过代理类的 invoke 方法把服务需要的 接口类名,方法名,请求参数 通过 Socket 发送给服务端;接收服务端处理的结果
三:具体实现的代码
(1)服务端的接口声明
public interface IHello { String sayHello(String string); }
(2)服务端接口的实现(真正干活的类)
public class HelloServiceImpl implements IHello{ @Override public String sayHello(String string) { // TODO Auto-generated method stub return "你好:" + string; } }
(3)服务端的服务类
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; public class RpcServer { private static final HashMap<String, Class<?>> serviceRegistry = new HashMap<>(); private int port; public RpcServer(int port) { this.port =port; } public RpcServer register(Class serviceInterface, Class impl) { serviceRegistry.put(serviceInterface.getName(), impl); return this; } public void run() throws IOException { ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress (port)); System.out.println("start server"); ObjectInputStream input =null; ObjectOutputStream output =null; Socket socket=null; try { while(true){ socket = server.accept (); input =new ObjectInputStream(socket.getInputStream()); String serviceName = input.readUTF(); String methodName = input.readUTF(); System.out.println ("客户端调用了 " + methodName + "方法"); Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); Object[] arguments = (Object[]) input.readObject(); Class serviceClass = serviceRegistry.get(serviceName); if (serviceClass == null) { throw new ClassNotFoundException(serviceName + " not found"); } Method method = serviceClass.getMethod(methodName, parameterTypes); Object result = method.invoke(serviceClass.newInstance(), arguments); output = new ObjectOutputStream (socket.getOutputStream()); output.writeObject(result); } } catch (Exception e){ e.printStackTrace(); } } public static void main(String[] args) throws IOException { new RpcServer (8888).register(IHello.class,HelloServiceImpl.class).run(); } }
(4)客户端的实现
import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.InetSocketAddress; import java.net.Socket; import com.cs.rpc.nativ.server.IHello; public class RpcClientProxy<T> implements InvocationHandler { private Class<T> serviceInterface;//被调用者的接口声明 private InetSocketAddress addr;//被调用者的地址(ip+port) public RpcClientProxy(Class<T> serviceInterface, String ip,String port) { this.serviceInterface = serviceInterface; this.addr = new InetSocketAddress(ip, Integer.parseInt ( port )); } public T getClientIntance(){ return (T) Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = null; ObjectOutputStream output = null; ObjectInputStream input = null; try { // 2.创建Socket客户端,根据指定地址连接远程服务提供者 socket = new Socket(); socket.connect(addr); // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者 output = new ObjectOutputStream(socket.getOutputStream()); output.writeUTF(serviceInterface.getName()); output.writeUTF(method.getName()); output.writeObject(method.getParameterTypes()); output.writeObject(args); // 4.同步阻塞等待服务器返回应答,获取应答后返回 input = new ObjectInputStream(socket.getInputStream()); return input.readObject(); } finally { if (socket != null) socket.close(); if (output != null) output.close(); if (input != null) input.close(); } } public static void main(String[] args) { RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","8888"); IHello hello = (IHello) client.getClientIntance (); System.out.println (hello.sayHello ( "socket rpc" )); } }