第10章 Dubbo 代理层的设计与实现

image.png

本节介绍 Dubbo 十层架构中的 Proxy 层。

image.png
  • ProxyFactory:代理工厂接口;
  • StubProxyFactoryWrapper:代理工厂装饰类(封装了对 stublocal 的处理逻辑),会在获取 ProxyFactory 具体子类时进行 AOP;
  • AbstractProxyFactory:代理工厂模板类(封装了获取组装接口的功能,用于创建动态代理),提供了模板方法;
  • JavassistProxyFactory:基于 Javassist 实现的代理工厂;
  • JdkProxyFactory:基于 JDK 动态代理实现的代理工厂;
  • AbstractProxyInvoker:最终封装的代理 Invoker,其子类内部发起真正的调用;
  • InvokerInvocationHandler:Proxy 发起调用时,会调用该类的 invoke(...),在该 invoke(...) 方法中,默认会调用 MockClusterInvoker 的 invoke(...),之后一路进行调用。

一、代理工厂接口 ProxyFactory

@SPI("javassist")
public interface ProxyFactory {
    /**
     * 使用端:consumer
     *
     * 创造一个代理,用于服务引用创建代理
     * @param invoker会被proxy调用的第一层Invoker,默认是 MockClusterInvoker
     * @return proxy 代理对象
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * 使用端:provider
     *
     * 创建一个Invoker,默认是代理Invoker -- AbstractProxyInvoker 的子类对象
     * @param <T> 接口 eg. com.alibaba.dubbo.demo.DemoService
     * @param proxy ref实例, eg. emoServiceImpl实例
     * @param type interface eg. com.alibaba.dubbo.demo.DemoService
     * @param url -- 
     *       injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true...
     *       registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider...&export=dubbo://10.213.11.98:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true...
     * @return invoker,默认是代理Invoker -- AbstractProxyInvoker 的子类对象
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}

二、代理工厂装饰类 StubProxyFactoryWrapper

public class StubProxyFactoryWrapper implements ProxyFactory {
    // 真正的ProxyFactory具体子类(JavassistProxyFactory/JdkProxyFactory)
    private final ProxyFactory proxyFactory;
    
    // 具有父类SPI接口(ProxyFactory)的单参构造器,所以该类是一个Wrapper类,会在getExtension获取ProxyFactory具体子类时进行aop
    public StubProxyFactoryWrapper(ProxyFactory proxyFactory) {
        this.proxyFactory = proxyFactory;
    }

    /**
     * 使用端:consumer
     */
    @Override
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        // 1. 调用 ProxyFactory 获取代理
        T proxy = proxyFactory.getProxy(invoker);
        // 2. 如果不是泛化接口,处理 stub 和 local
        ...
        return proxy;
    }

    /**
     * 使用端:provider
     */
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
        return proxyFactory.getInvoker(proxy, type, url);
    }
}

三、代理工厂模板类 AbstractProxyFactory

public abstract class AbstractProxyFactory implements ProxyFactory {
    @Override
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        /**
         * 1. 构造接口参数,默认只有 invoker.getInterface()(eg. DemoService), EchoService.class 两个接口
         */
        ...
        Class<?>[] interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
        ...

        /**
         * 2. 调用子类的实现去创建代理
         */
        return getProxy(invoker, interfaces);
    }

    /**
     * 提供给子类的抽象方法
     */
    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);

}

四、JdkProxyFactory

public class JdkProxyFactory extends AbstractProxyFactory {
    // 使用端:consumer
    @Override
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        // 使用JDK方式创建Java动态代理,创建了动态代理的逻辑处理类 InvokerInvocationHandler,并且传入了 MockClusterInvoker
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }

    // 使用端:provider
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // 创建真正的Invoker代理
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 获取真正的方法Method,proxy=DemoServiceImpl实例
                Method method = proxy.getClass().getMethod(methodName, parameterTypes);
                // 执行真正的方法
                return method.invoke(proxy, arguments);
            }
        };
    }
}

五、JavassistProxyFactory

public class JavassistProxyFactory extends AbstractProxyFactory {
    // 使用端:consumer
    @Override
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        // 使用 com.alibaba.dubbo.common.bytecode.Proxy 创建代理,创建了动态代理的逻辑处理类 InvokerInvocationHandler,并且传入了 MockClusterInvoker
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    // 使用端:provider
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // wrapper:通过动态生成一个真实的服务提供者(DemoServiceImpl)的wrapper类,来避免反射调用
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass());
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 直接调用wrapper,wrapper底层调用DemoServiceImpl
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

首先来看下 consumer 端:

Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))

这里首先调用 Proxy.getProxy(interfaces) 获取到一个创建代理的工厂类 com.alibaba.dubbo.common.bytecode.Proxy0,如下:

package com.alibaba.dubbo.common.bytecode;

import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.Proxy;
import com.alibaba.dubbo.common.bytecode.proxy0;
import java.lang.reflect.InvocationHandler;

public class Proxy0 extends Proxy implements ClassGenerator.DC {
    public Object newInstance(InvocationHandler invocationHandler) {
        return new proxy0(invocationHandler);
    }
}

之后调用了 Proxy0#newInstance 方法,创建了一个 com.alibaba.dubbo.common.bytecode.proxy0 实例,该实例就是最终的 DemoService 的代理对象。

DemoService demoService = (DemoService) context.getBean("demoService");

这里的 demoService 就是上述的 com.alibaba.dubbo.common.bytecode.proxy0 实例。

package com.alibaba.dubbo.common.bytecode;

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

public class proxy0 implements EchoService, DemoService {
    public static Method[] methods;
    private InvocationHandler handler;

    public String sayHello(String string) {
        Object[] arrobject = new Object[]{string};
        Object object = this.handler.invoke(this, methods[0], arrobject);
        return (String)object;
    }

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

    public proxy0() {
    }

    public proxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }
}
  • proxy0 实现的接口就是 AbstractProxyFactory 中获取的接口;
  • 当调用 proxy0#sayHello 时,实际上其内部执行的是 InvokerInvocationHandlerr#invoke,来看一下 InvokerInvocationHandler。

六、代理逻辑处理类 InvokerInvocationHandler

public class InvokerInvocationHandler implements InvocationHandler {
    /**
     * 第一个被Proxy调用的Invoker,默认为MockClusterInvoker
     */
    private final Invoker<?> invoker;

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ...
        // 1. 创建请求参数RpcInvocation
        // 2. 执行调用
        // 3. 对调用结果进行重建recreate():若响应有异常,直接抛异常;否则返回响应
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

七、Invoker代理 AbstractProxyInvoker

public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
    // 真实对象 ref, eg. DemoServiceImpl
    private final T proxy;
    // 接口类型,eg. DemoService
    private final Class<T> type;
    ...
    public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
        ...
        this.proxy = proxy;
        this.type = type;
        ...
    }
   ...
    /**
     * 进行调用
     * @param invocation 请求参数
     * @return 返回结果
     * @throws RpcException
     */
    @Override
    public Result invoke(Invocation invocation) throws RpcException {
        try {
            // 1. 调用子类发起请求
            // 2. 包装响应为 RpcResult
            return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
        } catch (InvocationTargetException e) {
            return new RpcResult(e.getTargetException());
        } catch (Throwable e) {
            throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

    // 子类覆写的真正调用的方法
    protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
}

AbstractProxyInvoker 的子类在 JdkProxyFactory#getInvoker(...)JavassistProxyFactory#getInvoker(...) 中进行创建的,来看下JavassistProxyFactory#getInvoker(...)

    // 使用端:provider
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // wrapper:通过动态生成一个真实的服务提供者(DemoServiceImpl)的wrapper类,来避免反射调用
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass());
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 直接调用wrapper,wrapper底层调用DemoServiceImpl
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

再贴下最终生成的 wrapper 类实例(com.alibaba.dubbo.common.bytecode.Wrapper0)。

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.alibaba.dubbo.demo.DemoService;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class Wrapper0 extends Wrapper implements ClassGenerator.DC {
    ...
    /**
     * @param object 实现类ref,eg. DemoServiceImpl
     * @param string 方法名称
     * @param arrclass 参数类型
     * @param arrobject 参数值
     * @return 调用返回值
     * @throws java.lang.reflect.InvocationTargetException
     */
    public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
        DemoService demoService;
        try {
            demoService = (DemoService)object;
        } catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable);
        }
        try {
            if ("sayHello".equals(string) && arrclass.length == 1) {
                return demoService.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.alibaba.dubbo.demo.DemoService.").toString());
    }
    ...
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容