利用java实现简单的RPC服务调用

一、前言

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

二、实现思路

之前看了一下dubbo的底层实现,发现dubbo的服务调用是通过动态代理+socket进行远程调用的。它通过javassit直接根据接口生成相关的代理类的字节码文件并加载到内存中,然后通过NIO非阻塞式的进行socket的服务传输和调用。所以,下面将会利用javassit+socket+io实现一个简单的rpc服务。

三、消费端代码

1,构建实力类,用作消息的传输。

public class MsgBean implements Serializable {
    // 调用方的类名称
    private String className;
    //调用方法名
    private String methodName;
    //方法的参数类型
    private Class[] methodParmType;
    //方法参数
    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 Class[] getMethodParmType() {
        return methodParmType;
    }

    public void setMethodParmType(Class[] methodParmType) {
        this.methodParmType = methodParmType;
    }

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

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

2.构建接口代理类的父类,其中rpcRuest()方法用于构建msgBean,并通过socket连接远程的服务获取方法调用结果

public class ProxyBase {
    /**
     * 通过socker请求获取数据信息
     * @param className
     * @param paramTypes
     * @param returnType
     * @param args
     * @return
     */
    public static Object rpcQuest(String className,String methodName, String paramTypes,String returnType,Object[] args){
        Object obj = null;
        try{
            MsgBean msgBean = new MsgBean();
            msgBean.setClassName(className);
            msgBean.setMethodName(methodName);
            String[] parTypes = paramTypes.split(",");
            Class[] classes = new Class[parTypes.length];
            for (int i = 0; i < parTypes.length; i++) {
                classes[i] = getClass(parTypes[i]);
            }
            msgBean.setMethodParmType(classes);
            msgBean.setParams(args);
            Socket socket = new Socket("localhost",10086);
            ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
            out.writeObject(msgBean);
            socket.shutdownOutput();
            if(!returnType.equals("void")){
                ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                obj = in.readObject();
                socket.shutdownInput();
                in.close();
            }
            out.close();
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 返回数据
     * @param obj
     * @param T
     * @param <T>
     * @return
     */
    public  static  <T> T returnVal(Object obj ,Class<T> T){
        return (T)obj;
    }
    /**
     * 根据名称获取class对象
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    public  static Class getClass(String className) throws ClassNotFoundException {
        return Class.forName(className);
    }

3、构建生成代理类的工厂

package main.rpc.consumer;

import javassist.*;

import java.util.Map;

public class ProxyFactory<T> {
    private Class t;
    public ProxyFactory(Class t){
        this.t = t;
    }
    private static final String PROXYFREIX = "$ProxyFactory";
    private static final String PROXYSUFFIX = "Impl";
    public T getProxyObject(){
        T proxyObject = null;
        try{
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass(getPackName()+"."+getProxyObjectName());
            //设置代理类的父类
            ctClass.setSuperclass(pool.getCtClass(ProxyBase.class.getName()));
            //设置代理类继承的接口
            CtClass inter = pool.getCtClass(getPackName()+"."+t.getSimpleName());
            CtClass[] intes = new CtClass[]{inter};
            ctClass.setInterfaces(intes);
            //测试新增的方法
            CtMethod ctNewMethod = CtNewMethod.make("public void test(){ System.out.println(\"新加的test方法\"); }",ctClass);
            ctClass.addMethod(ctNewMethod);
            //实现接口的各个方法
            CtMethod[] methods = inter.getDeclaredMethods();
            for (CtMethod method : methods) {
                CtMethod cm = new CtMethod(method.getReturnType(),method.getName(),method.getParameterTypes(),ctClass);
                String returnType = method.getReturnType().getName();
                String paramsTypes = "";
                for (CtClass aClass : method.getParameterTypes()) {
                    paramsTypes=paramsTypes+aClass.getName()+",";
                }
                paramsTypes = paramsTypes.substring(0,paramsTypes.lastIndexOf(","));
                StringBuilder sb = new StringBuilder("{");
                sb.append("String className=\""+t.getName()+"\";");
                sb.append("String methodName=\""+method.getName()+"\";");
                sb.append("String returnType=\""+returnType+"\";");
                sb.append("String paramsTypes=\""+paramsTypes+"\";");
                sb.append("Object[] args = new Object[]{");
                for(int i=1;i<=method.getParameterTypes().length;i++){
                    sb.append("$"+i);
                    if(i!=method.getParameterTypes().length){
                        sb.append(",");
                    }
                }
                sb.append("};");
                sb.append("Object obj=quest(className,methodName,paramsTypes,returnType,args");

                sb.append(");");
                if(!returnType.equals("void")){
                    sb.append("return ("+returnType+")obj;");
                }
                sb.append("}");
                cm.setBody(sb.toString());
                ctClass.addMethod(cm);
            }
            Class aClass = ctClass.toClass();
            proxyObject = (T)aClass.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return proxyObject;
    }
    /**
     * 获取报名
     * @return
     */
    public  String getPackName(){
        Package  pag = t.getPackage();
        return pag.getName();
    }

    /**999
     * 获取代理对象的名称
     * @return
     */
    public String getProxyObjectName(){
        return PROXYFREIX+t.getSimpleName()+PROXYSUFFIX;
    }

    public static void main(String[] args) throws InterruptedException {
        ProxyFactory<Student> proxy = new ProxyFactory<>(Student.class);
        Student student = proxy.getProxyObject();
        Map<String,String>  result = student.handupTask("HEllo 客户端");
        System.out.println(result);
    }

4、测试的接口

package main.rpc.consumer;

import java.util.Map;

/**
 * 调用方接口
 */
public interface Student {
     Map<String,String> handupTask(String str);
}

四、生产端代码

1、接口的实现类

package main.rpc.product;

import java.util.HashMap;
import java.util.Map;

public class StudentIml implements Student {

    @Override
    public Map<String,String> handupTask(String str) {
        Map<String,String> result  = new HashMap<>();
        result.put("你好啊","6666");
        result.put("测试通过啦","ouye");
        return result;
    }
}

 2、socket 服务端

package main.rpc.product;

import main.rpc.consumer.MsgBean;

import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class SocketServer {
    private static Map<String,String> propertis = new HashMap<>();
    static {
        propertis.put("main.rpc.Student","main.rpc.product.StudentIml");
    }
    public static void main(String[] args) throws  Exception {
        ServerSocket serverSocket = new ServerSocket(10086);
        System.out.println("等待客户端连接...");
        while (true){
            Socket socket =serverSocket.accept();
            System.out.println("客户端连接成功");
            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
            //获取接收的方法调用信息
            MsgBean msg = (MsgBean) inputStream.readObject();
            System.out.println("接收导的消息为:========"+msg);
            socket.shutdownInput();
            //根据方法的信息利用反射执行方法
            Class cl = Class.forName(propertis.get(msg.getClassName()));
            Method method = cl.getMethod(msg.getMethodName(),msg.getMethodParmType());
            Object obj = method.invoke(cl.newInstance(),msg.getParams());
            //如果方法不是void,则将结果回写客户端
            if(!method.getReturnType().getName().equals("void")){
                ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
                out.writeObject(obj);
                socket.shutdownOutput();
                out.close();
            }
            inputStream.close();
        }
    }
}

 五、结束语

基本思路就是消费者和生产者建立一个socket连接,消费方把调用的接口信息,方法名称,还有参数封装为一个对象,通过流传输到生产方,生产方根据方法调用的信息通过反射执行具体的方法,然后将结果回馈给消费者。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值