上一篇文章仔細的分析了 ,由 refer
方法 獲取的 代理對象的過程,以及最後獲取到的代理對象的結構,但是結尾比較草,本節仔細分析 字節碼生成的代理對象。
結構
上一篇文章結尾草草的給出了 代理對象的結構圖,但是並沒有對(T) PROXY_FACTORY.getProxy(invoker)
進行 整體上的分析:
首先在 Dubbo 的 ProxyFactory中,有兩個字節碼工具類,一個是JdkProxyFatory
,另一個是 JavassistProxyFactory
。
具體SPI 文件如下:
stub=org.apache.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory
並且默認使用的是 JavassistProxyFactory
作爲字節碼工具。
StubProxyFactoryWrapper
則主要是要執行優先於 ProxyFactory
的一些邏輯,這裏主要是在 getProxy
對 配置了 stub
和 local
屬性 進行一些額外處理。
在 JavassistProxyFactory中的構造方法如下:
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
上面構造方法主要是使用字節碼工具,將多個 interfaces對象(包括了 EchoService)生成一個代理對象,再使用 InvokerInvocationHandler
包裝起來。
ProxyFactory$Adaptive 源碼
通過一定方式,獲取到了 ProxyFactory$Adaptive
源碼,便於我們後面分析:
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0, arg1);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}
}
PROXY_FACTORY.getProxy(invoker) 詳解
AbstractProxyFactory 代碼示例:
@Override
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
// 不是泛化調用
return getProxy(invoker, false);
}
@Override
public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
Class<?>[] interfaces = null;
String config = invoker.getUrl().getParameter(INTERFACES);
if (config != null && config.length() > 0) {
String[] types = COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
interfaces = new Class<?>[types.length + 2];
interfaces[0] = invoker.getInterface();
interfaces[1] = EchoService.class;
for (int i = 0; i < types.length; i++) {
// TODO can we load successfully for a different classloader?.
interfaces[i + 2] = ReflectUtils.forName(types[i]);
}
}
}
if (interfaces == null) {
// 加入EchoService.class
interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
}
if (!GenericService.class.isAssignableFrom(invoker.getInterface()) && generic) {
// 加入GenericService.class
int len = interfaces.length;
Class<?>[] temp = interfaces;
interfaces = new Class<?>[len + 1];
System.arraycopy(temp, 0, interfaces, 0, len);
interfaces[len] = com.alibaba.dubbo.rpc.service.GenericService.class;
}
return getProxy(invoker, interfaces);
}
以下將一步一步,鑽進getProxy 看其具體實現:
- 由
ProxyFactory$Adaptive
,會先檢查參數。 - 通過
proxy
參數獲取使用的代理工廠,沒有則使用默認的javassist
,使用ExtensionLoader
的 SPI 方式獲取。 - 在
Adaptive
類中,獲取的extension
爲 使用StubProxyFactoryWrapper
包裝後的ProxyFactory
,所以會先執行StubProxyFactoryWrapper
的getProxy
方法,而是否會執行 具體ProxyFactory
的getProxy
方法,則需要看Wrapper
類的邏輯。
- 進入
StubProxyFactoryWrapper
的getProxy
,最終會先調用AbstractProxyFactory
,這裏面的getProxy
方法主要是判斷是否需要往代理生成類中再加入GenericService
用於泛化調用。 - 而後調用子類的
getProxy
,這裏使用JavassistProxyFactory
爲例:
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
- 使用字節碼工具,將傳入的interfaces類,以及 參數
InvokerInvocationHandler
,動態生成一個新的代理類並返回。
這裏爲什麼是多個呢?在使用Dubbo 的EchoService 及 泛化調用時,都是使用強轉的形式,所以這裏就傳入多個interfaces,才保證了強轉不會出錯。 - 在使用 javassist 構造
Proxy.getProxy
時候,截取了字節碼class 反編譯後的 java 代碼,可以便於理解
在具體的JavassistProxyFactory
的public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces)
依次會生成兩個類:一個是Proxy0
的包裝類,另一個是proxy0
,即具體功能存放類。
proxy0 代理類
public class proxy0 implements DC, EchoService, HelloService {
public static Method[] methods;
private InvocationHandler handler;
public String hello(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[0], var2);
return (String)var3;
}
public Object $echo(Object var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[1], var2);
return (Object)var3;
}
public proxy0() {
}
public proxy0(InvocationHandler var1) {
this.handler = var1;
}
}
Proxy0 代理類
public class Proxy0 extends Proxy implements DC {
public Object newInstance(InvocationHandler var1) {
return new proxy0(var1);
}
public Proxy0() {
}
}
分析在 JavassistProxyFactory
中的 以下方法:
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
從上面代碼中可以有以下收穫:
Proxy.getProxy(interfaces)
返回的是一個Proxy0
對象,注意是大寫的P- 最後調用
Proxy0
的newInstance
方法,實例化一個包裝類型的proxy0
,注意是小寫的 - dubbo 裏面的
EchoService
或者 泛化調用,都是通過javassist
字節碼工具,以實現方法形式實現,所以纔可以在業務層面強轉成功。 - 對於返回的代理類,也實現對應 refer 的接口,例如上述實現的
HelloService
。 - DC 是dynamic code 縮寫,只是一個標識,說明是動態生成的類。
- 對於手動執行方法,都是調用
InvokerInvocationHandler
的invoke
方法
而對於 InvokerInvocationHandler
中invoker 及後面調用邏輯,且看下一篇文章分析。
覺得博主寫的有用,不妨關注博主公衆號: 六點A君。
哈哈哈,Dubbo小吃街不迷路: