Dubbo源碼(6)-動態代理技術源碼解析(2)

本文主要參考自Dubbo官方文檔、Dubbo項目源碼以及網絡文章和相關書籍,並附上自身的一些理解,如有遺漏或錯誤,還望海涵並指出。謝謝!

------本文基於Dubbo-2.6.1版本

一.Dubbo中的動態代理

1.1、Dubbo Invoker領域模型

在說Dubbo動態代理之前,先來看看Dubbo的Invoker領域模型。

任何框架或組件,總會有核心領域模型,比如:Spring 的 Bean,Struts 的 Action,Dubbo 的 Service,Napoli 的 Queue 等等。這個核心領域模型及其組成部分稱爲實體域,它代表着我們要操作的目標本身。實體域通常是線程安全的,不管是通過不變類,同步狀態,或複製的方式。

服務域也就是行爲域,它是組件的功能集,同時也負責實體域和會話域的生命週期管理, 比如 Spring 的 ApplicationContext,Dubbo 的 ServiceManager 等。服務域的對象通常會比較重,而且是線程安全的,並以單一實例服務於所有調用。

什麼是會話?就是一次交互過程。會話中重要的概念是上下文,什麼是上下文?比如我們說:“老地方見”,這裏的“老地方”就是上下文信息。爲什麼說“老地方”對方會知道,因爲我們前面定義了“老地方”的具體內容。所以說,上下文通常持有交互過程中的狀態變量等。會話對象通常較輕,每次請求都重新創建實例,請求結束後銷燬。

簡而言之:把元信息交由實體域持有,把一次請求中的臨時狀態由會話域持有,由服務域貫穿整個 過程。

百度中關於領域模型的解釋:

領域模型是對領域內的概念類或現實世界中對象的可視化表示。 又稱概念模型、領域對象模型、分析對象模型。 它專注於分析問題領域本身,發掘重要的業務領域概念,並建立業務領域概念之間的關係。

Invoker是Dubbo 領域模型中非常重要的一個概念,很多設計思路都是向它靠攏。這就使得Invoker滲透在整個實現代碼裏。而Invoker的實現是基於動態代理的,這也是本文要講解的重點。

1.2、Invoke在RPC過程中的作用

在整個Dubbo關於RPC通信過程的代碼中出現了很多個Invoker,Invoker直譯爲執行器,那麼這些Invoker的作用是什麼呢?

下面來看一張圖,簡化了Dubbo RPC過程中的其他組件,來直觀地看Invoker在這個過程中的作用:

在這裏插入圖片描述

可以看出,在服務提供端中,Invoker封裝了具體的實現服務類。

當服務消費端需要通過RPC調用這個服務時,生成proxy調用對應的Invoker,藉助網絡通知到服務提供端Exporter,然後Exporter調用Invoker執行具體的服務邏輯。

可以看出,Invoker實質上就是由動態代理生成並封裝了網絡連接和數據處理的邏輯,以屏蔽底層的實現。這就是DUbbo動態代理技術的實際運用了。

二.RPC調用流程

在看源碼之前,先來從宏觀的層面瞭解下整個調用的流程,這裏忽略了很多細節,只展示最重要的實現,如下圖:

在這裏插入圖片描述

整體的流程如下:

  1. 客戶端通過RPC調用Service接口的方法
  2. 通過動態代理生成一個Proxy代理對象,該對象實現了Service接口,內容大致如下:
public class proxy0 implements ClassGenerator.DC, EchoService, Service {
    public static Method[] methods;
    private InvocationHandler handler
    public void bye(Object paramObject) {
       Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramObject;
       Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
    }
    public String hello(String paramString){ Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramString;
       Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
       return (String)localObject;
    }
    public Object $echo(Object paramObject) {
       Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramObject;
       Object localObject = this.handler.invoke(this, methods[2], arrayOfObject);
       return (Object)localObject;
    }
    public proxy0() {
        public proxy0(InvocationHandler paramInvocationHandler) {
            this.handler = paramInvocationHandler; 
        } 
    }

該類通過dubbo-common模塊的bytecode模塊的 Proxy類使用Javassis動態代理技術生成。

代理類首先實現了Service接口,然後所有的重寫方法調用都是集中在了InvocationHandlerinvoke方法中執行,這裏實質上就是調用了代理對象(封裝了許多RPC細節)。

  1. 服務端接的Protocol收到了這個RPC調用。
  2. Protocol獲取到被調用的Exporter對象
  3. Exporter對象獲取到Invoker代理對象
  4. Invoker代理對象執行Wrapper包裝類對象中對應的方法。實質上Wrapper對象內含有Service實現對象,如以下代碼:
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;
       public static Class[] mts1;
       public static Class[] mts2;

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

       public boolean hasProperty(String paramString)
       {
         return pts.containsKey(paramString);
       }

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

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

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

       public void setPropertyValue(Object paramObject1, String paramString, Object paramObject2)
       {
         ServiceImpl w;
         try
         {
           w = (ServiceImpl)paramObject1;
         }
         catch (Throwable localThrowable)
         {
           throw new IllegalArgumentException(localThrowable);
         }
         if (paramString.equals("test01"))
         {
           w.test01 = ((String)paramObject2);
           return;
         }
         if (paramString.equals("demoDAO"))
         {
           localServiceImpl.setDemoDAO((DemoDAO)paramObject2);
           return;
         }
         throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
       }

       public Object getPropertyValue(Object paramObject, String paramString)
       {
         ServiceImpl w;
         try
         {
           w = (ServiceImpl)paramObject;
    }
    catch (Throwable localThrowable)
        {throw new IllegalArgumentException(localThrowable);
        }
        if (paramString.equals("test01")) {return localServiceImpl.test01;
        }
        throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
    }
    public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject)
    throws InvocationTargetException
      {ServiceImpl w;
      try
    {
        w = (ServiceImpl)paramObject;
    }
      catch (Throwable localThrowable1)
      {
        throw new IllegalArgumentException(localThrowable1);
      }
      try
    {
        if ("hello".equals(paramString) && paramArrayOfClass.length == 1) {
            return w.hello((String)paramArrayOfObject[0]);
        }
        if ("bye".equals(paramString) && paramArrayOfClass.length == 1)
        {w.bye((Object)paramArrayOfObject[0]);
        return null;
        }
        if ("setDemoDAO".equals(paramString) && paramArrayOfClass.length == 1)
        {w.setDemoDAO((DemoDAO)paramArrayOfObject[0]);
        return null;
        }
    }
      catch (Throwable localThrowable2)
    {
        throw new InvocationTargetException(localThrowable2);
    }
      throw new NoSuchMethodException("Not found method \"" + paramString + "\" in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
    }
}

該包裝類由dubbo-common模塊的bytecode模塊的Wrapper類使用Javassist動態代理技術生成。

可以看到到了這一步,其實就是在調用包裝類中包裝的實現類的具體方法了。

三.動態代理相關源碼解析

關於Dubbo的動態代理技術的使用,相關的源碼集中在dubbo-rpc模塊以及dubbo-common模塊下的bytecode包。

dubbo-rpc遠程調用模塊包含了各種協議的抽象,以及動態代理,只包含一對一的調用,不關心集羣的管理。

3.1、ProxyFactory

ProxyFactory接口位於dubbo-rpc模塊下的dubbo-rpc-api子模塊,定義了獲取Proxy的方法,以SPI機制做動態拓展,默認使用的是JavassistProxyFactory作爲拓展實現類(Javassist做底層的動態代理技術,性能優於Jdk動態代理)。

  • ProxyFactory
@SPI("javassist")
public interface ProxyFactory {

    /**
     * 獲取指定的proxy
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * 獲取指定的Invoker
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
  • 實現關係圖
    在這裏插入圖片描述
3.1.1、AbstractProxyFactory
  • AbstractProxyFactory
public abstract class AbstractProxyFactory implements ProxyFactory {

    /*
     *   傳入invoker獲取proxy
     */
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        // 接口數組
        Class<?>[] interfaces = null;
        // 獲取invoker的url,再獲取url中的interfaces配置
        String config = invoker.getUrl().getParameter("interfaces");
        // 解析接口配置
        if (config != null && config.length() > 0) {
            // 獲取到接口全限定名數組
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                // 額外申請接口數組長度+2
                interfaces = new Class<?>[types.length + 2];
                // 第一個位置放置invoker自身實現的接口
                interfaces[0] = invoker.getInterface();
                // EchoService接口用於回聲測試
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i++) {
                    // 使用反射生成接口class
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        if (interfaces == null) {
            interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
        }
        // 模板方法模式,讓具體實現類實現getProxy(invoker, interfaces)的邏輯
        return getProxy(invoker, interfaces);
    }

    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
}
3.1.2、JavassistProxyFactory

com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactoryProxyFactory的默認拓展實現類:

  • JavassistProxyFactory
/**
 * JavaassistRpcProxyFactory,ProxyFactory默認拓展實現類
 */
public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    /*
    *   獲取proxy,這裏需要看Proxy類和InvokerInvocationHandler的源碼
     */
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    /*
    *   獲取invoker,不能夠獲取類名含有$的proxy
     */
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        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);
            }
        };
    }

}

3.2、InvokerInvocationHandler

com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler基於Jdk的InvocationHandler做了一層封裝實現:

  • InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler {

    private final Invoker<?> invoker;

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

    /*
    *   執行proxy的方法
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 獲取方法名
        String methodName = method.getName();
        // 獲取方法參數
        Class<?>[] parameterTypes = method.getParameterTypes();
        // 如果proxy爲Object,則直接使用method執行
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        // 下面三個方法統一使用invoker直接調用
        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.invoke的方式來執行
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

}

3.3、AbstractProxyInvoker

com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker實現了Invoker,可以獲取到RPC調用的執行結果:

  • AbstractProxyInvoker
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {

    // 被代理的接口實現類
    private final T proxy;
    // 被代理的接口
    private final Class<T> type;
    // 傳入URL對象
    private final URL url;

    /*
    *   構造方法
     */
    public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
        if (proxy == null) {
            throw new IllegalArgumentException("proxy == null");
        }
        if (type == null) {
            throw new IllegalArgumentException("interface == null");
        }
        if (!type.isInstance(proxy)) {
            throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
        }
        this.proxy = proxy;
        this.type = type;
        this.url = url;
    }

    public Class<T> getInterface() {
        return type;
    }

    public URL getUrl() {
        return url;
    }

    public boolean isAvailable() {
        return true;
    }

    public void destroy() {
    }

    /*
    *   執行代理方法,獲取到RPC調用結果
     */
    public Result invoke(Invocation invocation) throws RpcException {
        try {
            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;

    @Override
    public String toString() {
        return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString());
    }


}
  • RpcResult
public class RpcResult implements Result, Serializable {

    private static final long serialVersionUID = -6925924956850004727L;
    // RPC調用結果
    private Object result;

    private Throwable exception;
    // 額外附加信息
    private Map<String, String> attachments = new HashMap<String, String>();

    public RpcResult() {
    }

    public RpcResult(Object result) {
        this.result = result;
    }

    public RpcResult(Throwable exception) {
        this.exception = exception;
    }

    public Object recreate() throws Throwable {
        if (exception != null) {
            throw exception;
        }
        return result;
    }

    /**
     * @see com.alibaba.dubbo.rpc.RpcResult#getValue()
     * @deprecated Replace to getValue()
     */
    @Deprecated
    public Object getResult() {
        return getValue();
    }

    /**
     * @see com.alibaba.dubbo.rpc.RpcResult#setValue(Object)
     * @deprecated Replace to setValue()
     */
    @Deprecated
    public void setResult(Object result) {
        setValue(result);
    }

    public Object getValue() {
        return result;
    }

    public void setValue(Object value) {
        this.result = value;
    }

    public Throwable getException() {
        return exception;
    }

    public void setException(Throwable e) {
        this.exception = e;
    }

    public boolean hasException() {
        return exception != null;
    }

    public Map<String, String> getAttachments() {
        return attachments;
    }

    /**
     * Append all items from the map into the attachment, if map is empty then nothing happens
     *
     * @param map contains all key-value pairs to append
     */
    public void setAttachments(Map<String, String> map) {
        if (map != null && map.size() > 0) {
            attachments.putAll(map);
        }
    }

    public String getAttachment(String key) {
        return attachments.get(key);
    }

    public String getAttachment(String key, String defaultValue) {
        String result = attachments.get(key);
        if (result == null || result.length() == 0) {
            result = defaultValue;
        }
        return result;
    }

    public void setAttachment(String key, String value) {
        attachments.put(key, value);
    }

    @Override
    public String toString() {
        return "RpcResult [result=" + result + ", exception=" + exception + "]";
    }
}

3.4、bytecode包

上述的代碼都基於dubbo-rpc-api子模塊進行分析,下面基於dubbo-common模塊的bytecode包,基於Javassit動態編譯技術做了高性能的動態代理實現,用以生成wrapperproxy的代碼。

// TODO

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章