实现一个简单的RPC本地调用

1.RPC简介
RPC的全称是Remote process Call,即远程过程调用。其实现包括客户端和服务端,即服务的调用方与服务的提供方。服务调用方发送RPC请求到服务提供方,服务提供方根据调用方提供的参数执行请求方法,将执行结果返回到调用方,一次
RPC调用完成。

2.代码部分
服务接口类

package com.rpc;

/**
 * 服务接口定义
 * @Description
 * @author LH
 * @date 2018年7月5日下午10:47:44
 *
 */
public interface EchoService {
    String echo(String ping);
}
package com.rpc;

/**
 * 服务接口实现
 * @Description
 * @author LH
 * @date 2018年7月5日下午10:48:02
 *
 */
public class EchoServiceImpl implements EchoService {

    @Override
    public String echo(String ping) {
        return ping !=null?ping+"--> I am ok ":" I am ok ";
    }

}
package com.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;

/**
 * 服务发布者,运行在服务端,供其他消费者调用
 * @Description
 * @author LH
 * @date 2018年7月5日下午10:44:36
 *
 */
public class RpcExporter {

    public static Executor executor =Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    /**
     * 静态方法
     * @param hostName
     * @param port
     * @throws Exception
     */
    public static void exporter(String hostName,int port) throws Exception{
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(hostName,port));
        try{
            while(true){
                executor.execute(new ExportTask(serverSocket.accept()));
            }
        }finally{
            serverSocket.close();
        }
    }

    public static class ExportTask implements  Runnable{
        private Socket client = null;

        private ExportTask(Socket socket) {
            super();
            this.client = socket;
        }

        public void run() {
            ObjectInputStream input=null;
            ObjectOutputStream output =null;
            try {
                //读取服务信息
                input = new ObjectInputStream(client.getInputStream());
                //接口名称
                String interfaceName = input.readUTF();
                //方法名称
                String methodName = input.readUTF();
                //参数类型
                Class<?> [] parameterType = (Class<?> []) input.readObject();
                //参数对象
                Object [] argument = (Object []) input.readObject();
                //得到接口的class
                Class server = Class.forName(interfaceName);
                //取得要调用的方法
                Method method = server.getMethod(methodName, parameterType);
                //获取服务实现的对象
                Object result = method.invoke(server.newInstance(), argument);
                //将对象写入到二进制流中
                output = new ObjectOutputStream(client.getOutputStream());
                output.writeObject(result);
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                if(input!=null){
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                if(null !=output){
                    try {
                        output.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if(null != client){
                    try {
                        client.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

package com.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;

/**
 * 服务代理类,运行在客户端,通过代理调用远程服务提供者,将结果进行封装返回给本地消费者
 * @Description
 * @author LH
 * @date 2018年7月5日下午10:45:02
 *
 * @param <S>
 */
public class RpcImporter<S> {

    @SuppressWarnings("unchecked")
    public S importr(final Class<?> serverClass,final InetSocketAddress address){
        return (S) Proxy.newProxyInstance(serverClass.getClassLoader(), new Class<?>[]{serverClass.getInterfaces()[0]},
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {

                        Socket socket = null;
                        ObjectOutputStream objectOutputStream = null;
                        ObjectInputStream objectInputStream = null;
                        try {
                            //socket连接
                             socket=new Socket();
                             socket.connect(address);
                             objectOutputStream = new ObjectOutputStream(socket.getOutputStream());

                             //将方法名称和参数传递到远端
                             objectOutputStream.writeUTF(serverClass.getName());//写入接口名称
                             objectOutputStream.writeUTF(method.getName());//写入方法名称
                             objectOutputStream.writeObject(method.getParameterTypes());//写入参数类型
                             objectOutputStream.writeObject(args);//写入参数

                             //从远端获取方法执行的结果
                             objectInputStream = new ObjectInputStream(socket.getInputStream());
                            return objectInputStream.readObject();
                        } finally{
                            if(null !=socket){
                                socket.close();
                            }
                            if(null !=objectOutputStream){
                                objectInputStream.close();
                            }
                            if(null !=objectInputStream){
                                objectInputStream.close();
                            }
                        }
                    }
                });
    }
}
package com.rpc;

import java.net.InetSocketAddress;

public class TestRpc {
    public static void main(String[] args) {
        //创建一个异步发布服务端的线程,用于接收RPC客户端的请求
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    RpcExporter.exporter("localhost", 8080);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        ).start();

        //创建客户端代理类,构造RPC请求参数,发起RPC请求
        RpcImporter<EchoService> importer = new RpcImporter<EchoService>();
        EchoService echoService = importer.importr(EchoServiceImpl.class, new InetSocketAddress("localhost",8080));
        System.out.println(echoService.echo("Are you ok ?"));
    }
}

3.测试结果
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值