RPC入门(一):RPC java代码简单实现

来源:互联网 发布:易语言qq空间秒赞源码 编辑:程序博客网 时间:2024/05/19 02:25

1.RPC概念

     全程 Remote Procedure Call Protocol 即远程调用协议。它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。(来自百度百科)
(图片来源:互联网)

  •      服务消费方(client)调用以本地调用方式调用服务;
  •     client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  •     client stub找到服务地址,并将消息发送到服务端;
  •     server stub收到消息后进行解码;
  •     server stub根据解码结果调用本地的服务;
  •     本地服务执行并将结果返回给server stub;
  •     server stub将返回结果打包成消息并发送至消费方;
  •     client stub接收到消息,并进行解码;
  •     服务消费方得到最终结果。
如上图:如果client调用sayHello()方法,给人的感觉就像在调用本地方法一样,执行方法---返回数据。RPC屏蔽了底层通信、协议处理,让调用者不用关心具体实现的细节。

2.RPC框架组成

     从上图中我们知道RPC框架需要从下面几方面考虑:
  •      通信模型:服务消费方消费服务提供方提供的服务时,需要进行通信?通信一般采用TCP/UDP 或者 HTTP。
  •      服务定位:客户端该怎么找到服务提供方的服务?一般通过:IP、端口、具体方法名。
  •      远程对象代理:消费方如何调用RPC服务?实际上是通过远程方法的本地代理实现调用的。
  •      序列化:调用时如何传递数据?我们知道底层通信都是传输的字节流,因此我们需要将传递的对象序列化进行传输。


3.RPC框架的JAVA的简单实现

  •      通信模型:我们可以采用java的BIO或者NIO实现tcp连接。
  •      服务定位:我们只是简单实现直接写死 端口 和 ip,不去实现发现服务。
  •      远程对象代理:java中可以实现字节码或者动态代理实现。
  •      序列化:java原生序列化实现。

rpc-interface:服务接口定义。
rpc-provider:服务提供者,实现服务接口,依赖interface。
rpc-client: 服务消费方,依赖interface。

3.1 接口定义

package cc.hu.test.rpc.facade;public interface HelloRPCService {String sayHello(String name);}

3.2:服务提供

服务接口实现:
package cc.hu.test.rpc.provider.impl;import cc.hu.test.rpc.facade.HelloRPCService;public class HelloRPCServiceImpl implements HelloRPCService {@Overridepublic String sayHello(String name) {return "Hi, RPC  I  want " + name;}}

服务server接口定义:
package cc.hu.test.rpc.provider;public interface RPCProvider {/**停止服务*/void stop();/**启动RPC服务*/void start();/**获得服务端口*/int getPort();/**注册服务*/void regist(Class<?> serviceInterface, Class<?> serviceImpl);boolean isRunning();}

服务server接口实现:

package cc.hu.test.rpc.provider;import java.io.IOException;import java.net.ServerSocket;import java.util.HashMap;import java.util.Map;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class RPCProviderImpl implements RPCProvider {//private static ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());//使用线程池private static Map<String, Class<?>> SERVICE_MAP = new HashMap<String, Class<?>>();private boolean isStop = false;private static int port = 28080;public static Class<?> getServiceClass(String serviceName) {return SERVICE_MAP.get(serviceName);}@Overridepublic void stop() {this.isStop = true;}@Overridepublic void start() {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(port);System.out.println("开启RPC测试服务@" + String.valueOf(port));while (!isStop) {Thread t = new Thread(new RPCProviderHandler(serverSocket.accept()));//每一次调用新建一个线程t.start();//exec.execute(new RPCProviderHandler(serverSocket.accept()) );//使用线程池}} catch (IOException e) {e.printStackTrace();} finally {if (null != serverSocket)try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}@Overridepublic int getPort() {return port;}@Overridepublic void regist(Class<?> serviceInterface, Class<?> serviceImpl) {SERVICE_MAP.put(serviceInterface.getName(), serviceImpl);}@Overridepublic boolean isRunning() {return !isStop;}}

服务server调用处理:
package cc.hu.test.rpc.provider;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.Socket;public class RPCProviderHandler implements Runnable {Socket socket;public RPCProviderHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {ObjectInputStream input = null;ObjectOutputStream output = null;try {input = new ObjectInputStream(socket.getInputStream());String serviceName = input.readUTF();String methodName = input.readUTF();Class<?>[] parameterTypes = (Class<?>[]) input.readObject();Object[] parameters = (Object[]) input.readObject(); Class<?> serviceImpl = RPCProviderImpl.getServiceClass(serviceName);//获取实现类if (null == serviceImpl)throw new ClassNotFoundException(serviceName);Method method = serviceImpl.getMethod(methodName, parameterTypes);//获取调用方法String result = (String) method.invoke(serviceImpl.newInstance(), parameters);//将执行调用后的结果输出output = new ObjectOutputStream(socket.getOutputStream());output.writeObject(result);} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} finally {try {if (output != null) {output.flush();output.close();}if (input != null)input.close();if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}}
服务Main:
package cc.hu.test.rpc.provider;import cc.hu.test.rpc.facade.HelloRPCService;import cc.hu.test.rpc.provider.impl.HelloRPCServiceImpl;/** * RPC * */public class App {    public static void main( String[] args )    {    RPCProvider provider = new RPCProviderImpl();    provider.regist(HelloRPCService.class, HelloRPCServiceImpl.class);//注册rpc服务    provider.start();//启动服务端    }}

3.3 消费方:

消费方代理实现:
package cc.hu.test.rpc.client;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 RPCClient<T> {@SuppressWarnings("unchecked")public static <T> T getRemoteProxyObj(final Class<?> serviceInterface, final int port, final String address) {return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface}, new InvocationHandler() {@SuppressWarnings("resource")@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Socket socket = null;ObjectInputStream input = null;ObjectOutputStream output = null;socket = new Socket(address, port);output = new ObjectOutputStream(socket.getOutputStream());output.writeUTF(serviceInterface.getName());output.writeUTF(method.getName());output.writeObject(method.getParameterTypes());output.writeObject(args);input = new ObjectInputStream(socket.getInputStream());String callRet = (String) input.readObject();return callRet;}});}}
消费方main
package cc.hu.test.rpc.client;import java.io.IOException;import cc.hu.test.rpc.facade.HelloRPCService;/** * Hello world! * */public class App {    public static void main( String[] args )    {        HelloRPCService service = RPCClient.getRemoteProxyObj(HelloRPCService.class, 28080, "192.168.2.62");        byte[] buffer = new byte[512];        try {        System.out.print("请输入任意字符:");System.in.read(buffer);String name = new String(buffer);System.out.println(service.sayHello(name));} catch (IOException e) {e.printStackTrace();}    }}

只是简单模拟RPC调用,没有考虑重连、性能、服务发现、注册中心等机制。