文章目錄
本文主要參考自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
動態代理技術生成。
可以看到到了這一步,其實就是在調用包裝類中包裝的實現類的具體方法了。
三.動態代理相關源碼解析
關於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.JavassistProxyFactory
是ProxyFactory
的默認拓展實現類:
- 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動態編譯技術做了高性能的動態代理實現,用以生成wrapper
與proxy
的代碼。
// TODO