stone

基于Socket的rpc简单实践
无论是分布式程序还是微服务,都需要涉及到远程进程的调用,这就需要借助rpc的力量。rpc的目的是将网络通信的细节进...
扫描右侧二维码阅读全文
26
2016/12

基于Socket的rpc简单实践

无论是分布式程序还是微服务,都需要涉及到远程进程的调用,这就需要借助rpc的力量。rpc的目的是将网络通信的细节进行封装,使调用远程服务像调用本地服务一样方便。实现rpc的方法有很多种,但是解决的问题基本相同:

  1. 调用和被调用两者之间通信的建立
  2. 参数的序列化和传递
  3. 运行结果的获取

下面是自己写的一个简单的DEMO,利用socket和java的动态代理实现简单的rpc。

程序分为client和worker,client启动之后会启动一个线程专门进行监听8080端口,并管理连接进来的socket连接。worker启动之后会建立一个socket连接到client。

client通过ServiceFactory获取到一个远程调理Service,通过调用Service的接口,然后将这个接口的相关信息,参数通过socket连接传送到worker上,通过反射调用该函数,并将调用的结果返回给client端,完成调用。

关键程序如下:

//调用远程服务的代码
  UserService userService = ServiceFactory.getUserService();
  User user = userService.getUser();
  System.out.println(user);
//工厂类,返回服务的远程代理
public class ServiceFactory {
    public static UserService getUserService(){
    //实现一个空接口
        UserService userService = new UserService() {
            public User getUser() {
                return null;
            }
        };

        ClassLoader serviceCL = UserService.class.getClassLoader();
        Class<?>[] serviceInterface = userService.getClass().getInterfaces();
        DynamicProxy proxy = new DynamicProxy(UserService.class);

        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(serviceCL,serviceInterface,proxy);
        return userServiceProxy;
    }
}
//动态代理,实现socket网络通信
public class DynamicProxy implements InvocationHandler {
    Class obj = null;

    public DynamicProxy(Class obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ObjectInputStream objIS = null;
        ObjectOutputStream objOS = null;

        Socket worker = Client.getSocket();

        objOS = new ObjectOutputStream(worker.getOutputStream());
        objOS.writeObject(obj.getName());
        objOS.writeObject(method.getName());
        objOS.writeObject(args);

        objIS = new ObjectInputStream(worker.getInputStream());
        Object rs = objIS.readObject();

        return rs;
    }
}
// worker端基于反射实现函数调用
public static Object handleRequest(String className,String methodName,Object[] args){
        try {
            Class service = Class.forName(className + "Impl");
            Constructor constructor = service.getDeclaredConstructor();
            Object obj = constructor.newInstance();

            Method method = service.getDeclaredMethod(methodName);
            Object rs = method.invoke(obj, args);

            return rs;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }

代码比较简单,源码可以看这里👈👈👈👈

这里有两个小坑:

  1. 对于socket,inputStream,outputStream只能获取一次,当获取两次之后就会出问题
  2. 接口是不能进行动态代理的,接口不能实例化
Last modification:September 7th, 2018 at 08:21 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment