模拟基本的RPC框架代码

10 篇文章 0 订阅
2 篇文章 0 订阅

最近晚上没事,加上工作上要使用,所以开始自己学习RPC框架,目前写了一个基本的,便于理解,后续往里面添加内容。

**

服务提供方:

**

服务接口代码:

package zhm.rpc.server;

public interface IServer {
    public String testMethod(String arg);
}

接口实现类:

/**
 * rpcServerImpl.java
 * zhm.rpc.server
 * 2017年10月9日下午8:44:06
 *
 */
package zhm.rpc.server;

/**
 * @author zhuheming
 * rpcServerImpl
 * 2017年10月9日下午8:44:06
 */
public class rpcServerImpl implements IServer {

    /* (non-Javadoc)
     * @see zhm.rpc.server.IServer#testMethod(java.lang.String)
     */
    @Override
    public String testMethod(String arg) {
        // TODO Auto-generated method stub
        return "hello, "+arg;
    }

}

反射类:
主要用于接收服务消费方发起的远程调用请求,得到method和args,就是方法和参数,再利用反射方式执行该方法,返回执行结果。

这里反射使用了commons.lang3包中的MethodUtils工具类实现。

/**
 * serverReflect.java
 * zhu.rpc.reflect
 * 2017年10月9日下午9:24:47
 *
 */
package zhu.rpc.reflect;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.commons.lang3.reflect.MethodUtils;


/**
 * @author zhuheming
 * serverReflect
 * 2017年10月9日下午9:24:47
 */
public class ServerReflect implements Runnable{

    private Object object;
    private int port;

    public ServerReflect(Object object,int port){
        this.object=object;
        this.port=port;
    }
    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        // TODO Auto-generated method stub
        //新建连接
            //SocketConnect sc=new SocketConnect();         
            //Socket socket=sc.connect("127.0.0.1", port);
            try {
                ServerSocket ss=new ServerSocket(port);

            while(true){
                try {
                    final Socket socket=ss.accept();
                    //建立输入
                    ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
                    try{
                        //得到方法名和参数列表
                        String method=ois.readUTF();
                        Object[] args=(Object[])ois.readObject(); 
                        System.out.print(method+"  "+args.toString());
                        //反射得到对应方法的执行结果 
                        Object resultObject=MethodUtils.invokeExactMethod(object, method, args);
                        ObjectOutputStream oos=new ObjectOutputStream(socket.getOutputStream());
                        try{
                            //返回结果
                            oos.writeObject(resultObject);
                        }catch(Exception e){
                            oos.writeObject(e);
                            e.printStackTrace();
                        }finally{
                            oos.close();
                        }
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }finally{
                        ois.close();
                    }
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
    //private static Thread serverThread=new Thread();

    //public void waittingServer(Class<T> serverClass,int port)

}

测试入口:
省得麻烦,直接使用8081端口,用一个Thread来运行等待服务消费端的调用。

/**
 * test.java
 * zhm.rpc.test
 * 2017年10月9日下午10:18:33
 *
 */
package zhm.rpc.test;

import zhm.rpc.server.IServer;
import zhm.rpc.server.rpcServerImpl;
import zhu.rpc.reflect.ServerReflect;

/**
 * @author zhuheming
 * test
 * 2017年10月9日下午10:18:33
 */
public class testServer {
    public static void main(String args[]) throws InterruptedException{
        IServer is=new rpcServerImpl();
        Thread serverThread=new Thread(new ServerReflect(is,8081));
        serverThread.start();
        serverThread.join();
    }

}

**

服务消费方:

**

socket连接器,这里使用了一个连接接口IConnect,方便以后如果使用多种连接方式可以抽象

package zhm.rpc.connect;

import java.net.Socket;


/**
 * socket连接器
 * @author zhuheming
 * socketConnet
 * 2017年9月28日下午11:29:24
 */
public class SocketConnect implements IConnect {

    @Override
    public Socket connect(String host, int port) {
        // TODO Auto-generated method stub
        //判断输入参数
        if(!"".equalsIgnoreCase(host)&&port!=0){
            Socket socket=null;
            try{
                socket=new Socket(host,port);

            }catch(Exception e){
                e.getStackTrace();
            }
            return socket;
        }else{
            return null;
        }

    }

    public void close(Object connectObject){
        if(connectObject!=null){
            try{
                Socket socket=(Socket)connectObject;
                socket.close();
            }catch(Exception e){
                e.getStackTrace();
            }
        }
    }


}

服务消费方的动态代理实现:
思路是将服务提供方的IServer接口生成动态代理类,使用动态代理类执行执行IServer的接口方法时,会调用invoke方法,在invoke方法中,远程连接消费提供方,将方法名称和参数发送给服务提供方,由服务提供方返回执行结果。


/**
 * cosumeProxy.java
 * zhm.rpc.proxy
 * 2017年9月29日上午12:03:30
 *
 */
package zhm.rpc.proxy;

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;

import zhm.rpc.connect.SocketConnect;

/**
 * @author zhuheming
 * cosumeProxy
 * 2017年9月29日上午12:03:30
 */
public class ConsumeProxy {
    //匿名内部类方法实现需要调用,所以host和port需要为final
    @SuppressWarnings("unchecked")
    public static <T> T consume(Class<T> interfaceClass,final String host,final int port){

        //先建立一个InvocationHandler接口的对象(实现内部方法)
        //InvocationHandler invocationHandler=;

        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass},new InvocationHandler(){

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
                //建立连接
                SocketConnect sc=new SocketConnect();
                Socket socket=sc.connect(host, port);
                //发送方法和参数
                ObjectOutputStream ops=new ObjectOutputStream(socket.getOutputStream());
                ops.writeUTF(method.getName());
                ops.writeObject(args);
                //接收返回
                ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
                Object getObject=ois.readObject();
                return getObject;
            }
    });
        //return null;

    }
}

服务提供方给的服务接口
注意,实现是在服务提供方,消费方只有接口

package zhm.rpc.server;

public interface IServer {
    public String testMethod(String arg);
}

服务消费方入口:

先生成代理类,再远程执行方法。

package zhm.rpc.test;

import zhm.rpc.proxy.ConsumeProxy;
import zhm.rpc.server.IServer;

public class Test {

    //远程调用服务端的testMethod方法,客户端只有接口,没有方法实现。
    public static void main(String args[]) throws InterruptedException{
        Object obj= ConsumeProxy.consume(IServer.class, "127.0.0.1", 8081);
        if(obj!=null){
            System.out.println(obj.getClass().getInterfaces().toString());
            //System.out.println(obj.toString());
            System.out.println("not null!");
        }else{
            System.out.println("null!");
        }
        IServer rpc=(IServer)obj;

        for(int i=0;i<100;i++){

            System.out.println(rpc.testMethod(""+i));
            Thread.sleep(1000);
        }
    }

}

好了,以上就是最简单的RPC远程执行框架,要想丰满起来,后续还要考虑很多,如自己实现序列化反序列化,软负载均衡,高可用NIO通讯方式,服务的解耦合IOC方式,以及服务治理,类似zk的服务发布等。

继续努力吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值