Dubbo源碼(5)-動態代理技術源碼解析(1)

本文主要參考自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動態代理技術生成。

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

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