一:什麼是RPCjava
遠程過程調用(Remote Procedure Call)。就是調用其餘業務方的方法的時候,就像是調用本身本地的方法同樣。服務器
二:java rpc實現簡介socket
服務端(使用反射)ide
(1)服務端寫一個接口和一個接口的實現。this
(2)服務端維護一個map,key爲接口的類名,value爲接口的實現類。編碼
(3)服務端經過 ServerSocket 接收客戶端發送過來的數據(接口的類名,方法名,請求參數).net
(4)服務端根據接口的類名和方法名獲得對應實現類的方法,經過反射調用服務代理
(5)把處理以後的結果經過 ServerSocket 返回給客戶端server
客戶端(動態代理)blog
(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" )); } }