Dubbo之ProxyFactory

王大爷 2021年09月05日 465次浏览

概述

在分析服务暴露和服务引用的都提到ProxyFactory,它是Dubbo的代理工厂,只定义了两个方法。

  • getInvoker,暴露服务时调用,将ref(真正的服务实现类)转化为Invoker
  • getProxy,引用服务时调用,将Invoker对象转化为proxy代理对象

Invoker

Invoker 是 Dubbo 领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得 Invoker 渗透在整个实现代码里,对于刚开始接触 Dubbo 的人,确实容易给搞混了。 下面我们用一个精简的图来说明最重要的两种 Invoker:服务提供 Invoker 和服务消费 Invoker:

上面是出自Dubbo的官方教程。

服务提供端的AbstractProxyInvoker,封装了真正的服务实现类,代理了它的方法。服务消费端的DubboInvoker等,封装了远程通信的逻辑。

Dubbo中对远程的调用是Invoker,调用服务真正的实现类也是Invoker。

ProxyFactory

Dubbo的代理工厂,Dubbo之所以能够宣传像调用本地服务一样调用远程服务,就是用它实现的。@SPI扩展接口,默认实现是JavassistProxyFactory,还有一个实现是JdkProxyFactory,最终都会被StubProxyFactoryWrapper包装。

@SPI("javassist")
public interface ProxyFactory {

    /**
     * 服务引用时调用
     * create proxy.
     *
     * @param invoker   Protocol生成的Invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * 服务暴露时调用
     * create invoker.
     *
     * @param <T>
     * @param proxy Service对象
     * @param type  Service类型
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

getInvoker

JavassistProxyFactory和JdkProxyFactory的返回的都是AbstractProxyInvoker,区别在于前者使用自动生成的类,包装了硬编码进行调用,后者则使用JDK反射机制进行调用。对于Dubbo来说都是Invoker,进行了统一的抽象,这样Dubbo框架就不需要关心服务的具体业务,全部交给AbstractProxyInvoker去封装。

真正调用服务的时候会执行Invoker#invoke(),而AbstractProxyInvoker会把调用转给真正的服务实现类。

JavassistProxyFactory

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    // TODO Wrapper类不能正确处理带$的类名
    // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
    // proxy.getClass()返回的是实现类的Class,type是接口的Class
    // Wrapper对象对方法的调用进行了包装,没有使用反射,
    // Wrapper是使用javassist动态生成类才进行方法调用的包装
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
    return new AbstractProxyInvoker<T>(proxy, type, url) {
        @Override
        protected Object doInvoke(T proxy, String methodName,
                                  Class<?>[] parameterTypes,
                                  Object[] arguments) throws Throwable {
            return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
        }
    };
}

某个Wrapper类的代码片段,没有用反射

public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException {
    DemoService var5;
    try {
        var5 = (DemoService)var1;
    } catch (Throwable var8) {
        throw new IllegalArgumentException(var8);
    }

    try {
        if ("sayHello".equals(var2) && var3.length == 1) {
            return var5.sayHello((String)var4[0]);
        }
    } catch (Throwable var9) {
        throw new InvocationTargetException(var9);
    }

    throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class cre.dubbo.demo.DemoService.");
}

JdkProxyFactory

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    return new AbstractProxyInvoker<T>(proxy, type, url) {
        @Override
        protected Object doInvoke(T proxy, String methodName,
                                  Class<?>[] parameterTypes,
                                  Object[] arguments) throws Throwable {
            // 使用反射调用
            Method method = proxy.getClass().getMethod(methodName, parameterTypes);
            return method.invoke(proxy, arguments);
        }
    };
}

getProxy

生成的代理类实现指定的服务接口(还会实现EchoService接口),因此消费端在使用代理对象的时候跟使用本地服务是一样的。JavassistProxyFactory和JdkProxyFactory的都使用到了InvokerInvocationHandler

InvokerInvocationHandler它的作用是将消费端的调用转到内部的Invoker#invoke()上

JavassistProxyFactory

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

JdkProxyFactory

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}

InvokerInvocationHandler

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    Class<?>[] parameterTypes = method.getParameterTypes();
    if (method.getDeclaringClass() == Object.class) {
        return method.invoke(invoker, args);
    }
    if ("toString".equals(methodName) && parameterTypes.length == 0) {
        return invoker.toString();
    }
    if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
        return invoker.hashCode();
    }
    if ("equals".equals(methodName) && parameterTypes.length == 1) {
        return invoker.equals(args[0]);
    }
    // Invoker进行Rpc调用
    return invoker.invoke(new RpcInvocation(method, args)).recreate();
}