一步一步了解RPC之客户端

  上文描述了服务端的实现,下面进行客户端的实现。

  客户端由于不能直接通过new进行服务端调用,需要使用服务端的代理类,而代理对象为服务端的接口,在demo中将服务端的接口类IHgHello拷贝一份到客户端中。

   上文中,已将服务的接口地址进行暴露,即localhost:8080端口,客户端实现服务端的代理类为RpcClientProxy。  RpcClientProxy是一个代理类,通过中动态代理实现对服务端接口的代理,它是对服务传输过程的封装。

  //这是调用方法      
  RpcClientProxy rpcClientProxy = new RpcClientProxy();
  IHgHello hgHello = rpcClientProxy.clientProxy(IHgHello.class,"localhost",8080);

public class RpcClientProxy {

    public <T> T clientProxy(Class<T> interfaceCls,String host,int port){
       return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),new Class<?>[]{interfaceCls},new RemoteInvocationHandler(host,port));
    }

}

 在代理方法中,真正处理业务的类为RemoteInvocationHandler,其实现了InvocationHandler接口:

public class RemoteInvocationHandler implements InvocationHandler {

    String host;
    int port;

    public RemoteInvocationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        RPCRequest request = new RPCRequest();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParams(args);

        RPCNetTransport rpcNetTransport = new RPCNetTransport(host,port);
        return rpcNetTransport.send(request);
    }
}

  不同JVM中进行数据的调用,需要将数据进行序列化和反序列化。在实现过程中,对调用方法进行了封装成RPCRequest类,通过RPCNetTransport进行数据的传输。

public class RPCRequest implements Serializable{

    private static final long serialVersionUID = -8532503063900121027L;

    private String className;
    private String methodName;
    private Object[] params;

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }
}
public class RPCNetTransport {

    String host;
    int port;

    public RPCNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }

    private Socket newSocket(){
        System.out.println("begin create connect  ");

        Socket socket = null;
        try{
            socket = new Socket(host,port);
        }catch (Exception e){
            throw new RuntimeException("build connect failed");
        }
        return socket;
    }

    public Object send (RPCRequest request){
        Socket socket = null;
        try{
            socket = newSocket();
            ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(request);
            outputStream.flush();

            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
            Object result = inputStream.readObject(); // 反序列化得到结果
            inputStream.close();
            outputStream.close();
            return  result;
        }catch (Exception e){
            throw new RuntimeException("send request exception:" + e);
        }finally {
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

最后在启动server端服务后,调用上面的调用方法,即可实现RPC的调用。

通过这个demo的实现,让我了解了RPC的实现方式以及调用过程,不过在此过程中也有几点需要改进:

1.服务端的接口层通过maven进行打包发布,方便版本升级和客户端引用;

2.服务端的服务发布可以采用注册中心的方式,对发布中心地址进行配置化;

3.服务端在接收客户端连接可以采用netty为通信框架,防止IO阻塞;

demo加强了理解,后续在改进后继续实现,应用于项目实战。这个demo的下载地址为:

https://gitee.com/lihegang/rpc-server.git

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值