深入浅出RPC,通俗代码理解dubbo

背景

现在的java后端服务都是类似微服务这种,面向接口编程,不管是开源的,dubbo, spring cloud ,还是各家公司自研的,基本上都是以rpc协议这种

思考

虽然平时都在用,直接照搬之前的开发模式,定义接口,开发逻辑,好像也可以,不过我在想,如果我自己要实现一个rpc框架如何实现呢,这让我陷入了深深的思考

测试RPC(dubbo)

这是抽丝剥茧后理解dubbo的最简洁的代码了

  @Test
    public void export() {
        AnnotationService ref = new AnnotationServiceImpl();
        JavassistProxyFactory proxyFactory = new JavassistProxyFactory();
        //这个地方 会生成AnnotationService 接口代理类
        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) AnnotationService.class, URL.valueOf("dubbo://127.0.0.1:9020/" + AnnotationService.class.getName() + "?codec=exchange"));
        Protocol protocol = new DubboProtocol();
        //导出服务,这个地方底层代码有一个关键是开启了netty,作为通信协议,很关键
        protocol.export(invoker);
        //客户端接口
        AnnotationService clientService = proxyFactory.getProxy(protocol.refer(AnnotationService.class, URL.valueOf("dubbo://127.0.0.1:9020/" + AnnotationService.class.getName() + "?codec=exchange").addParameter("timeout",
                3000L)));
        System.out.println(clientService.sayHello("aa"));


    }

分析服务端代理类

代理类这个玩意老是在各种资料中看到,我倒要看看这个到底是个啥,这是得到的源码

package com.alibaba.dubbo.common.bytecode;

import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.NoSuchMethodException;
import com.alibaba.dubbo.common.bytecode.NoSuchPropertyException;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.dubbo.demo.AnnotationServiceImpl;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class Wrapper1
extends Wrapper
implements ClassGenerator.DC {
    public static String[] pns;
    public static Map pts;
    public static String[] mns;
    public static String[] dmns;
    public static Class[] mts0;

    @Override
    public String[] getPropertyNames() {
        return pns;
    }

    @Override
    public boolean hasProperty(String string) {
        return pts.containsKey(string);
    }

    public Class getPropertyType(String string) {
        return (Class)pts.get(string);
    }

    @Override
    public String[] getMethodNames() {
        return mns;
    }

    @Override
    public String[] getDeclaredMethodNames() {
        return dmns;
    }

    @Override
    public void setPropertyValue(Object object, String string, Object object2) {
        try {
            AnnotationServiceImpl annotationServiceImpl = (AnnotationServiceImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(string).append("\" filed or setter method in class com.dubbo.demo.AnnotationServiceImpl.").toString());
    }

    @Override
    public Object getPropertyValue(Object object, String string) {
        try {
            AnnotationServiceImpl annotationServiceImpl = (AnnotationServiceImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(string).append("\" filed or setter method in class com.dubbo.demo.AnnotationServiceImpl.").toString());
    }

    这是个重要的方法,客户端传来的请求,实际上最后就是到了这里调用,
    // 客户端实际上传来的参数实际上在一个map集合中,通过key,找到value,key实际上就是接口产生URL,value,
    // 说到底就是这个接口的实现类,调用后就把结果再返回 去
    public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
        AnnotationServiceImpl annotationServiceImpl;
        try {
            annotationServiceImpl = (AnnotationServiceImpl)object;
        }
        catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        try {
            if ("sayHello".equals(string) && arrclass.length == 1) {
                return annotationServiceImpl.sayHello((String)arrobject[0]);
            }
        }
        catch (Throwable throwable) {
            throw new InvocationTargetException(throwable);
        }
        throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(string).append("\" in class com.dubbo.demo.AnnotationServiceImpl.").toString());
    }
}

分析客户端代理类

客户端实际上的接口代理类是长这样

ClassLoader:                                                                                                                                                            
+-sun.misc.Launcher$AppClassLoader@18b4aac2                                                                                                                             
  +-sun.misc.Launcher$ExtClassLoader@6bf2d08e                                                                                                                           

Location:                                                                                                                                                               
/Users/wending/.m2/repository/com/alibaba/dubbo/2.6.8/dubbo-2.6.8.jar                                                                                                   

/*
 * Decompiled with CFR.
 * 
 * Could not load the following classes:
 *  com.dubbo.demo.AnnotationService
 */
package com.alibaba.dubbo.common.bytecode;

import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.rpc.service.EchoService;
import com.dubbo.demo.AnnotationService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class proxy0
implements ClassGenerator.DC,
AnnotationService,
EchoService {
    public static Method[] methods;
    private InvocationHandler handler;

    public proxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }

    public proxy0() {
    }

    @Override
    public Object $echo(Object object) {
        Object[] arrobject = new Object[]{object};
        Object object2 = this.handler.invoke(this, methods[1], arrobject);
        return object2;
    }

    //实际上调用 方法时走到了这里,通过代理类把消息打包传出去
    public String sayHello(String string) {
        Object[] arrobject = new Object[]{string};
        Object object = this.handler.invoke(this, methods[0], arrobject);
        return (String)object;
    }
}

再思考

  1. 客户端,服务端为什么要用动态代理类,代理首先是肯定是很多东西都要实现这个功能 ,用统一的功能来实现,为什么是动态呢,因为如果不用动态的话,你得每个类都去实现相同的代码,变成了静态代理,在rpc中,动态代理屏蔽掉接口以外的东西,里面的细节主要是就把从数据转换,传输
  2. 之前一直写业务代码,面试的时候问,用没用过代理,没用过,这里不就是活生生的例子嘛 ,看多好用,dubbo里面主要用Javassist 来实现代理,类生成器,可以参考这个 ClassGenerator源码

RPC核心问题

1.客户端用代理屏蔽掉接口的以外的东西,把数据请求发出来
2.服务端根据收到的信息,调用相应的接口类实现类处理请求信息
3.通信问题,可以借助第三方来实现,比如Netty

细节补充

  1. 查看代理类源码,通过arthas这个工具,阿里开源工具,很好用
  2. dubbo更多细节,移步官网,查看
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wending-Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值