本文主要參考自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調用流程
在看源碼之前,先來從宏觀的層面瞭解下整個調用的流程,這裏忽略了很多細節,只展示最重要的實現,如下圖:
整體的流程如下:
- 客戶端通過RPC調用Service接口的方法
- 通過動態代理生成一個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
接口,然後所有的重寫方法調用都是集中在了InvocationHandler
的invoke
方法中執行,這裏實質上就是調用了代理對象(封裝了許多RPC細節)。
- 服務端接的
Protocol
收到了這個RPC調用。 Protocol
獲取到被調用的Exporter
對象Exporter
對象獲取到Invoker
代理對象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
動態代理技術生成。
可以看到到了這一步,其實就是在調用包裝類中包裝的實現類的具體方法了。