学习dubbo源码-本地暴露

本地暴露


1 主要目的是获取exporter


2 获取JavassistProxyFactory来创建invoker
细节:com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);获取到的对象是StubProxyFactoryWrapper,在spi扩展点的时候说过,spi实现类含有接口构造会作为一个包装类,如果有多个包装类,会进行链式包装,并返回最后一个类。


3 对proxy进行包装并返回包装类,主要核心就是invokeMethod方法,Wrapper的invokeMethod方法是个抽象方法,需要对此方法进行实现,然后创建AbstractProxyInvoker实例返回


4 动态生成包装类(采用javassist生成,第一次才需要生成,之后直接从缓存取),主要是对invokeMethod抽象方法进行实现

  • 看他动态生成的实现方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
    com.alibaba.dubbo.demo.provider.DemoServiceImpl w;
    try {
    w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl) $1);
    } catch (Throwable e) {
    throw new IllegalArgumentException(e);
    }
    try {
    //调用时对接口方法判断
    if ("gude".equals($2) && $3.length == 1) {
    return ($w) w.gude((java.lang.String) $4[0]);
    }
    if ("sayHello".equals($2) && $3.length == 1) {
    return ($w) w.sayHello((java.lang.String) $4[0]);
    }
    } catch (Throwable e) {
    throw new java.lang.reflect.InvocationTargetException(e);
    }
    throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    }

Javassist中$w、$1含义:

详细含义信息请看这里


为什么要包装调用方法?

远程到提供者只会传给调用方法名称,如果不动态生成包装类,只能使用反射进行调用,反射相比直接调用方法,性能较低。

oracle官方反射介绍

5 8个默认过滤器,创建过滤链,对invoker进行相关操作


6 创建InjvmExporter并放到exporterMap中,不管远程暴露还是本地暴露,都会放到这个Map中。exporterMap.put(key, this)//本地暴露:key=com.alibaba.dubbo.demo.DemoService, this=InjvmExporter
远程暴露: exporterMap.put(key, this)//key=com.alibaba.dubbo.demo.DemoService:20880, this=DubboExporter


7 本地暴露完成