简单的RPC实现

来源:互联网 发布:淘宝双十一红包不中 编辑:程序博客网 时间:2024/05/21 09:10

/** *  * @ClassName: EchoService * @Description: 通过Java原生的序列化,socket通信,动态代理,和反射机制实现最简单的rpc框架 * 1服务提供者:它运行在服务端,负责提供服务接口定义和实现类 * 2服务发布者:它运行在RPC服务端,负责将本地服务发布成远程服务,供其他消费者调用 * 3本地服务代理:它运行在RPC客户端,通过代理调用远程服务提供者,然后将结果封装后返回给本地消费者 *  * @author: jkson * @date: 2016年10月9日 下午1:58:20 * */public interface EchoService {String echo(String ping);}/** *  * @ClassName: EchoServiceImpl * @Description: 通过Java原生的序列化,socket通信,动态代理,和反射机制实现最简单的rpc框架 * 1服务提供者:它运行在服务端,负责提供服务接口定义和实现类 * 2服务发布者:它运行在RPC服务端,负责将本地服务发布成远程服务,供其他消费者调用 * 3本地服务代理:它运行在RPC客户端,通过代理调用远程服务提供者,然后将结果封装后返回给本地消费者 * @author: jkson * @date: 2016年10月9日 下午1:58:10 * */public class EchoServiceImpl implements EchoService {@Overridepublic String echo(String ping) {return ping !=null?ping+"--> Hi i get it.":"i get it.";}}package jk.rpc;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.concurrent.Executor;import java.util.concurrent.Executors;/** *  * @ClassName: RpcExporter * @Description: 服务发布者的主要职责如下 * 1作为服务端,监听客户端的TCP链接,接收到新的TCP链接之后将其封装成TASk,由线程池执行 * 2将客户端发送的码流转换成对象,反射调用服务实现者,获取执行结果 * 3将执行结果对象反序列化,通过socket发送给客户端 * 4远程服务调用完成之后,释放socket等链接资源,防止句柄泄漏 * @author: jkson * @date: 2016年10月9日 下午1:57:56 * */public class RpcExporter {static Executor executor =Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public static void exporter(String hostName,int port)throws Exception{ServerSocket server =new ServerSocket();server.bind(new InetSocketAddress(hostName,port));try{while(true){System.out.println("等待访问");executor.execute(new ExporterTask(server.accept()));//此处是阻塞方法,调用一次阻塞到这里,有访问的时候走下,然后再次走到这里等待下次调用}}finally{server.close();}}private static class ExporterTask implements Runnable{Socket client=null;public ExporterTask(Socket client){this.client=client;}@Overridepublic void run() {ObjectInputStream intput=null;ObjectOutputStream output=null;try{System.out.println("准备接受数据");intput =new ObjectInputStream(client.getInputStream());String interfaceName = intput.readUTF();Class<?> service =  Class.forName(interfaceName);String methodName = intput.readUTF();Class<?>[] parameterTypes = (Class<?>[])intput.readObject();Object[]  arguments= (Object[])intput.readObject();Method method =service.getMethod(methodName, parameterTypes);Object result = method.invoke(service.newInstance(), arguments);output =new ObjectOutputStream(client.getOutputStream());output.writeObject(result);System.out.println("接收并执行完毕");}catch(Exception e){e.printStackTrace();}finally{System.out.println("释放服务器资源");if(output !=null){try{output.close();}catch(IOException e){e.printStackTrace();}}if(intput !=null){try{intput.close();}catch(IOException e){e.printStackTrace();}}if(client !=null){try{client.close();}catch(IOException e){e.printStackTrace();}}}}}}package jk.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.InetSocketAddress;import java.net.Socket;/** *  * @ClassName: RpcImporter * @Description:本地服务代理的主要功能如下: * 1将本地接口调用转换成JDk的动态代理,在动态代理中实现接口的远程调用 *  2创建Socket客户端,根据指定地址链接远程服务提供者 *  3将远程接口服务调用所需要的接口类,方法名,参数列表等编码后发给服务提供者、 *  4同步阻塞,等待服务端返回应答,获取应答之后返回 * @author: jkson * @date: 2016年10月9日 下午1:57:40 * * @param <S> */public class RpcImporter<S> {public S importer(final Class<?> serviceClass,final InetSocketAddress addr){return (S)Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[]{serviceClass.getInterfaces()[0]},new InvocationHandler(){public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{Socket socket =null;ObjectOutputStream output=null;ObjectInputStream intput=null;try{System.out.println("准备向服务器发送数据");socket=new Socket();socket.connect(addr);output=new ObjectOutputStream(socket.getOutputStream());output.writeUTF(serviceClass.getName());output.writeUTF(method.getName());output.writeObject(method.getParameterTypes());output.writeObject(args);intput=new ObjectInputStream(socket.getInputStream());System.out.println("发送完毕");return intput.readObject();}finally{System.out.println("释放客户端资源");if(socket !=null){socket.close();}if(output !=null){output.close();}if(intput !=null){intput.close();}}}});}}package jk.rpc;import java.net.InetSocketAddress;/** *  * @ClassName: RpcTest * @Description: 1首先创建一个异步发布服务端的线程并启动,用于接收RPC客户端的请求,根据请求参数调用服务实现类,返回结果给客户端 *  2创建客户端服务代理类,构造RPC请求参数,发起RPC调用,将调用结构输出到控制台上 * @author: jkson * @date: 2016年10月9日 下午1:57:14 * */public class RpcTest {public static void main(String[] args) {new Thread(new Runnable(){public void run(){try{RpcExporter.exporter("localhost",8088);}catch(Exception e){e.printStackTrace();}}}).start();RpcImporter<EchoService> importer =new RpcImporter<EchoService>();EchoService echo=importer.importer(EchoServiceImpl.class, new InetSocketAddress("localhost",8088));System.out.println("begin");System.out.println(echo.echo("Do you get it?"));System.out.println("end");}}下面是执行结果等待访问begin准备向服务器发送数据等待访问准备接受数据发送完毕接收并执行完毕释放服务器资源释放客户端资源Do you get it?--> Hi i get it.end


0 0