RPC通俗的讲就是在本地调用服务器端服务。而实现RPC框架用到的一项重要的技术就是动态代理技术,首先先讲一下为什么使用动态代理(不知道动态代理的 可以自行百度一下动态代理)技术
我们知道 在使用动态代理时有一个这样的方法
public Object invoke(Object proxy, Method method, Object[] args)
使用在客户端,使用动态代理代理客户端发送请求有两优点
(1) 能够不该变源码的情况下,与服务端进行交互。
(2)这一点也是为什么使用动态代理的重要原因 ,通过method拿到方法名,通过args拿到参数,以便服务端使用。
以下是我实现自己RPC的主演代码
package com.lin.rpc; 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.Socket; public class Consumer { /** * 使用代理技术,使每个方法在被调用前都在前面增加一系列操作 * @param interfaceClass * @param host * @param port * @param <T> * @return */ public static <T> T consumer(final Class<T> interfaceClass, final String host, final int port) { return (T) Proxy.newProxyInstance(interfaceClass.getClass().getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket(host, port); ObjectOutputStream os; ObjectInputStream is; try { os = new ObjectOutputStream(socket.getOutputStream()); is = new ObjectInputStream(socket.getInputStream()); os.writeUTF(method.getName()); os.writeObject(args); try { Object result = is.readObject(); if(result instanceof Throwable){ throw (Throwable) result; } return result; }finally { is.close(); os.close(); } }finally { socket.close(); } } }); } }
package com.lin.rpc; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; //服务方发布服务 public class ServerProvide { public static void provide(final Object service, int port) { ObjectInputStream objectInputStream; ObjectOutputStream objectOutputStream; try { ServerSocket serverSocket = new ServerSocket(10088); Socket clientsocket = serverSocket.accept(); try { InputStream inputStream = clientsocket.getInputStream(); objectInputStream = new ObjectInputStream(inputStream); objectOutputStream =new ObjectOutputStream(clientsocket.getOutputStream()); String methodName = objectInputStream.readUTF(); Object[] arguments = (Object[]) objectInputStream.readObject(); Class clazz = service.getClass(); Class[] classes = new Class[arguments.length]; for (int i=0;i<arguments.length;i++){ classes[i]=arguments.getClass(); } try { Object result = clazz.getDeclaredMethod(methodName, classes).invoke(service, arguments); objectOutputStream.writeObject(result); }catch ( Throwable t){ objectOutputStream.writeObject(t); objectOutputStream.close(); objectInputStream.close(); clientsocket.close(); } }finally { } } catch (Exception e) { e.printStackTrace(); } finally { } } }