Dubbo原始碼解析(二十三)遠端呼叫——Proxy
遠端呼叫——Proxy
目標:介紹遠端呼叫代理的設計和實現,介紹dubbo-rpc-api中的各種proxy包的原始碼。
前言
首先宣告叫做代理,代理在很多領域都存在,最形象的就是現在朋友圈的代理,廠家委託代理幫他們賣東西。這樣做廠家對於消費者來說就是透明的,並且代理可以自己加上一些活動或者銷售措施,但這並不影響到廠家。這裡的廠家就是委託類,而代理就可以抽象為代理類。這樣做有兩個優點,第一是可以隱藏代理類的實現,第二就是委託類和呼叫方的解耦,並且能夠在不修改委託類原本的邏輯情況下新增一些額外的處理。
代理分為兩種,靜態代理和動態代理。
- 靜態代理:如果代理類在程式執行前就已經存在,那麼這種代理就是靜態代理。
- 動態代理:代理類在程式執行時建立的代理方式。動態代理關係由兩組靜態代理關係組成,這就是動態代理的原理。
上述稍微回顧了一下靜態代理和動態代理,那麼dubbo對於動態代理有兩種方法實現,分別是javassist和jdk。Proxy 層封裝了所有介面的透明化代理,而在其它層都以 Invoker 為中心,只有到了暴露給使用者使用時,才用 Proxy 將 Invoker 轉成介面,或將介面實現轉成 Invoker,也就是去掉 Proxy 層 RPC 是可以 Run 的,只是不那麼透明,不那麼看起來像調本地服務一樣調遠端服務。我們來看看下面的圖:
我們能看到左邊是消費者的呼叫鏈,只有當消費者呼叫的時候,ProxyFactory才會通過Proxy把介面實現轉化為invoker,並且在其他層的呼叫都使用的是invoker,同樣的道理,在服務提供者暴露服務的時候,也只有在最後暴露給消費者的時候才會通過Proxy 將 Invoker 轉成介面。
動態代理的底層原理就是位元組碼技術,dubbo提供了兩種方式來實現代理:
- 第一種jdk,jdk動態代理比較簡單,它內建在JDK中,因此不依賴第三方jar包,但是功能相對較弱,當呼叫Proxy 的靜態方法建立動態代理類時,類名格式是“$ProxyN”,N代表第 N 次生成的動態代理類,如果重複建立動態代理類會直接返回原先建立的代理類。但是這個以“$ProxyN”命名的類是繼承Proxy類的,並且實現了其所代理的一組介面,這裡就出現了它的一個侷限性,由於java的類只能單繼承,所以JDK動態代理僅支援介面代理。
- 第二種是Javassist,Javassist是一款Java位元組碼引擎工具,能夠在執行時編譯生成class。該方法也是代理的預設方法。
原始碼分析
(一)AbstractProxyFactory
該類是代理工廠的抽象類,主要處理了一下需要代理的介面,然後把代理getProxy方法抽象出來。
public abstract class AbstractProxyFactory implements ProxyFactory {
@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 = Constants.COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
// 建立介面型別陣列
interfaces = new Class<?>[types.length + 2];
// 第一個放invoker的服務介面
interfaces[0] = invoker.getInterface();
// 第二個位置放回聲測試服務的介面類
interfaces[1] = EchoService.class;
// 其他介面迴圈放入
for (int i = 0; i < types.length; i++) {
interfaces[i + 1] = ReflectUtils.forName(types[i]);
}
}
}
// 如果介面為空,就是config為空,則是回聲測試
if (interfaces == null) {
interfaces = new Class<?>[]{invoker.getInterface(),EchoService.class};
}
// 如果是泛化服務,那麼在代理的介面集合中加入泛化服務型別
if (!invoker.getInterface().equals(GenericService.class) && generic) {
int len = interfaces.length;
Class<?>[] temp = interfaces;
interfaces = new Class<?>[len + 1];
System.arraycopy(temp,0,interfaces,len);
interfaces[len] = GenericService.class;
}
// 獲得代理
return getProxy(invoker,interfaces);
}
public abstract <T> T getProxy(Invoker<T> invoker,Class<?>[] types);
}
複製程式碼
邏輯比較簡單,就是處理了url中攜帶的interfaces的值。
(二)AbstractProxyInvoker
該類實現了Invoker介面,是代理invoker物件的抽象類。
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
// 呼叫了抽象方法doInvoke
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;
複製程式碼
該類最關鍵的就是這兩個方法,一個是invoke方法,呼叫了抽象方法doInvoke,另一個則是抽象方法。該方法被子類實現。
(三)InvokerInvocationHandler
該類實現了InvocationHandler介面,動態代理類都必須要實現InvocationHandler介面,而該類實現的是對於基礎方法不適用rpc呼叫,其他方法使用rpc呼叫。
public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
// 獲得方法名
String methodName = method.getName();
// 獲得引數型別
Class<?>[] parameterTypes = method.getParameterTypes();
// 如果方法引數型別是object型別,則直接反射呼叫
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker,args);
}
// 基礎方法,不使用 RPC 呼叫
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]);
}
// rpc呼叫
return invoker.invoke(new RpcInvocation(method,args)).recreate();
}
}
複製程式碼
(四)StubProxyFactoryWrapper
該類實現了本地存根的邏輯,關於本地存根的概念和使用在官方檔案中都有詳細說明。
public class StubProxyFactoryWrapper implements ProxyFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(StubProxyFactoryWrapper.class);
/**
* 代理工廠
*/
private final ProxyFactory proxyFactory;
/**
* 協議
*/
private Protocol protocol;
public StubProxyFactoryWrapper(ProxyFactory proxyFactory) {
this.proxyFactory = proxyFactory;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
@Override
public <T> T getProxy(Invoker<T> invoker,boolean generic) throws RpcException {
return proxyFactory.getProxy(invoker,generic);
}
@Override
@SuppressWarnings({"unchecked","rawtypes"})
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
// 獲得代理類物件
T proxy = proxyFactory.getProxy(invoker);
// 如果不是返回服務呼叫
if (GenericService.class != invoker.getInterface()) {
// 獲得stub的配置
String stub = invoker.getUrl().getParameter(Constants.STUB_KEY,invoker.getUrl().getParameter(Constants.LOCAL_KEY));
// 如果配置不為空
if (ConfigUtils.isNotEmpty(stub)) {
Class<?> serviceType = invoker.getInterface();
if (ConfigUtils.isDefault(stub)) {
// 根據local和stub來生成stub
if (invoker.getUrl().hasParameter(Constants.STUB_KEY)) {
stub = serviceType.getName() + "Stub";
} else {
stub = serviceType.getName() + "Local";
}
}
try {
// 生成stub類
Class<?> stubClass = ReflectUtils.forName(stub);
if (!serviceType.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());
}
try {
// 獲得構造方法,該構造方法必須是帶有代理的物件的引數
Constructor<?> constructor = ReflectUtils.findConstructor(stubClass,serviceType);
// 使用指定的初始化引數建立和初始化建構函式宣告類的新例項
proxy = (T) constructor.newInstance(new Object[]{proxy});
//export stub service
URL url = invoker.getUrl();
if (url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT)) {
url = url.addParameter(Constants.STUB_EVENT_METHODS_KEY,StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(),","));
url = url.addParameter(Constants.IS_SERVER_KEY,Boolean.FALSE.toString());
try {
// 暴露stub服務
export(proxy,(Class) invoker.getInterface(),url);
} catch (Exception e) {
LOGGER.error("export a stub service error.",e);
}
}
} catch (NoSuchMethodException e) {
throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(),e);
}
} catch (Throwable t) {
LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ",cause: " + t.getMessage(),t);
// ignore
}
}
}
return proxy;
}
@Override
public <T> Invoker<T> getInvoker(T proxy,Class<T> type,URL url) throws RpcException {
return proxyFactory.getInvoker(proxy,type,url);
}
private <T> Exporter<T> export(T instance,URL url) {
return protocol.export(proxyFactory.getInvoker(instance,url));
}
複製程式碼
該類裡面最重要的就是getProxy方法的實現,在該方法中先根據配置生成載入stub服務類,然後通過構造方法將代理的物件進行包裝,最後暴露該服務,然後返回代理類物件。
(五)JdkProxyFactory
該類繼承了AbstractProxyFactory,是jdk的代理工廠的主要邏輯。
public class JdkProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker,Class<?>[] interfaces) {
// 呼叫了 Proxy.newProxyInstance直接獲得代理類
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new InvokerInvocationHandler(invoker));
}
@Override
public <T> Invoker<T> getInvoker(T proxy,URL url) {
// 建立AbstractProxyInvoker物件
return new AbstractProxyInvoker<T>(proxy,url) {
@Override
protected Object doInvoke(T proxy,Object[] arguments) throws Throwable {
// 反射獲得方法
Method method = proxy.getClass().getMethod(methodName,parameterTypes);
// 執行方法
return method.invoke(proxy,arguments);
}
};
}
}
複製程式碼
不過邏輯實現比較簡單,因為jdk中都封裝好了,直接呼叫Proxy.newProxyInstance方法就可以獲得代理類。
(六)JavassistProxyFactory
該類是基於Javassist實現的動態代理工廠類。
public class JavassistProxyFactory extends AbstractProxyFactory {
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker,Class<?>[] interfaces) {
// 建立代理
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
@Override
public <T> Invoker<T> getInvoker(T proxy,URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
// 建立Wrapper物件
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy,Object[] arguments) throws Throwable {
// 呼叫方法
return wrapper.invokeMethod(proxy,methodName,parameterTypes,arguments);
}
};
}
}
複製程式碼
在這裡看不出什麼具體的實現,感覺看起來跟JdkProxyFactory差不多,下面我將講解com.alibaba.dubbo.common.bytecode.Proxy類的getProxy方法和com.alibaba.dubbo.common.bytecode.Wrapper類的getWrapper方法。
(七)Proxy#getProxy()
public static Proxy getProxy(Class<?>... ics) {
// 獲得代理類
return getProxy(ClassHelper.getClassLoader(Proxy.class),ics);
}
/**
* Get proxy.
*
* @param cl class loader.
* @param ics interface class array.
* @return Proxy instance.
*/
public static Proxy getProxy(ClassLoader cl,Class<?>... ics) {
// 最大的代理介面數限制是65535
if (ics.length > 65535)
throw new IllegalArgumentException("interface limit exceeded");
StringBuilder sb = new StringBuilder();
// 遍歷代理介面,獲取介面的全限定名並以分號分隔連線成字串
for (int i = 0; i < ics.length; i++) {
// 獲得類名
String itf = ics[i].getName();
// 判斷是否為介面
if (!ics[i].isInterface())
throw new RuntimeException(itf + " is not a interface.");
Class<?> tmp = null;
try {
// 獲得與itf對應的Class物件
tmp = Class.forName(itf,false,cl);
} catch (ClassNotFoundException e) {
}
// 如果通過類名獲得的型別跟ics中的型別不一樣,則丟擲異常
if (tmp != ics[i])
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
// 拼接類
sb.append(itf).append(';');
}
// use interface class name list as key.
String key = sb.toString();
// get cache by class loader.
Map<String,Object> cache;
synchronized (ProxyCacheMap) {
// 通過類載入器獲得快取
cache = ProxyCacheMap.get(cl);
if (cache == null) {
cache = new HashMap<String,Object>();
ProxyCacheMap.put(cl,cache);
}
}
Proxy proxy = null;
synchronized (cache) {
do {
Object value = cache.get(key);
// 如果快取中存在,則直接返回代理物件
if (value instanceof Reference<?>) {
proxy = (Proxy) ((Reference<?>) value).get();
if (proxy != null)
return proxy;
}
// 是等待生成的型別,則等待
if (value == PendingGenerationMarker) {
try {
cache.wait();
} catch (InterruptedException e) {
}
} else {
// 否則放入快取中
cache.put(key,PendingGenerationMarker);
break;
}
}
while (true);
}
// AtomicLong自增生成代理類類名字尾id,防止衝突
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null,ccm = null;
try {
ccp = ClassGenerator.newInstance(cl);
Set<String> worked = new HashSet<String>();
List<Method> methods = new ArrayList<Method>();
for (int i = 0; i < ics.length; i++) {
// 判斷是否為public
if (!Modifier.isPublic(ics[i].getModifiers())) {
// 獲得該類的包名
String npkg = ics[i].getPackage().getName();
if (pkg == null) {
pkg = npkg;
} else {
if (!pkg.equals(npkg))
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
// 把介面加入到ccp的mInterfaces中
ccp.addInterface(ics[i]);
// 遍歷每個類的方法
for (Method method : ics[i].getMethods()) {
// 獲得方法描述 這個方法描述是自定義:
// 例如:int do(int arg1) => "do(I)I"
// 例如:void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
String desc = ReflectUtils.getDesc(method);
if (worked.contains(desc))
continue;
// 如果集合中不存在,則加入該描述
worked.add(desc);
int ix = methods.size();
// 獲得方法返回型別
Class<?> rt = method.getReturnType();
// 獲得方法引數型別
Class<?>[] pts = method.getParameterTypes();
// 新建一句程式碼
// 例如Object[] args = new Object[引數數量】
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
// 每一個引數都生成一句程式碼
// 例如args[0] = ($w)$1;
// 例如 Object ret = handler.invoke(this,methods[3],args);
for (int j = 0; j < pts.length; j++)
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
code.append(" Object ret = handler.invoke(this,methods[" + ix + "],args);");
// 如果方法不是void型別
// 則拼接 return ret;
if (!Void.TYPE.equals(rt))
code.append(" return ").append(asArgument(rt,"ret")).append(";");
methods.add(method);
ccp.addMethod(method.getName(),method.getModifiers(),rt,pts,method.getExceptionTypes(),code.toString());
}
}
if (pkg == null)
pkg = PACKAGE_NAME;
// create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
// 新增靜態欄位Method[] methods
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
// 新增例項物件InvokerInvocationHandler hanler,新增引數為InvokerInvocationHandler的構造器
ccp.addConstructor(Modifier.PUBLIC,new Class<?>[]{InvocationHandler.class},new Class<?>[0],"handler=$1;");
// 新增預設無參構造器
ccp.addDefaultConstructor();
// 使用toClass方法生成對應的位元組碼
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null,methods.toArray(new Method[0]));
// create Proxy class.
// 生成的位元組碼物件為服務介面的代理物件
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class<?> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(),e);
} finally {
// release ClassGenerator
// 重置類構造器
if (ccp != null)
ccp.release();
if (ccm != null)
ccm.release();
synchronized (cache) {
if (proxy == null)
cache.remove(key);
else
cache.put(key,new WeakReference<Proxy>(proxy));
cache.notifyAll();
}
}
return proxy;
}
複製程式碼
Proxy是是生成代理物件的工具類,跟JdkProxyFactory中用到的Proxy不是同一個,JdkProxyFactory中的是jdk自帶的java.lang.reflect.Proxy。而該Proxy是dubbo基於javassit實現的com.alibaba.dubbo.common.bytecode.Proxy。該方法比較長,可以分開五個步驟來看:
- 遍歷代理介面,獲取介面的全限定名,並以分號分隔連線成字串,以此字串為key,查詢快取map,如果快取存在,則獲取代理物件直接返回。
- 由一個AtomicLong自增生成代理類類名字尾id,防止衝突
- 遍歷介面中的方法,獲取返回型別和引數型別,構建的方法體見註釋
- 建立工具類ClassGenerator例項,新增靜態欄位Method[] methods,新增例項物件InvokerInvocationHandler hanler,新增引數為InvokerInvocationHandler的構造器,新增無參構造器,然後使用toClass方法生成對應的位元組碼。
- 4中生成的位元組碼物件為服務介面的代理物件,而Proxy類本身是抽象類,需要實現newInstance(InvocationHandler handler)方法,生成Proxy的實現類,其中proxy0即上面生成的服務介面的代理物件。
(八)Wrapper#getWrapper
public static Wrapper getWrapper(Class<?> c) {
// 判斷c是否繼承 ClassGenerator.DC.class ,如果是,則拿到父類,避免重複包裝
while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
c = c.getSuperclass();
// 如果類為object型別
if (c == Object.class)
return OBJECT_WRAPPER;
// 如果快取裡面沒有該物件,則新建一個wrapper
Wrapper ret = WRAPPER_MAP.get(c);
if (ret == null) {
ret = makeWrapper(c);
WRAPPER_MAP.put(c,ret);
}
return ret;
}
private static Wrapper makeWrapper(Class<?> c) {
// 如果c不是似有類,則丟擲異常
if (c.isPrimitive())
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
// 獲得類名
String name = c.getName();
// 獲得類載入器
ClassLoader cl = ClassHelper.getClassLoader(c);
// 設定屬性的方法第一行public void setPropertyValue(Object o,String n,Object v){
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o,Object v){ ");
// 獲得屬性的方法第一行 public Object getPropertyValue(Object o,String n){
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o,String n){ ");
// 執行方法的第一行
StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o,Class[] p,Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
// 新增每個方法中被呼叫物件的型別轉換的程式碼
c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
Map<String,Class<?>> pts = new HashMap<String,Class<?>>(); // <property name,property types>
Map<String,Method> ms = new LinkedHashMap<String,Method>(); // <method desc,Method instance>
List<String> mns = new ArrayList<String>(); // method names.
List<String> dmns = new ArrayList<String>(); // declaring method names.
// get all public field.
// 遍歷每個public的屬性,放入setPropertyValue和getPropertyValue方法中
for (Field f : c.getFields()) {
String fn = f.getName();
Class<?> ft = f.getType();
// // 排除有static 和 transient修飾的屬性
if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
continue;
c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft,"$3")).append("; return; }");
c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
pts.put(fn,ft);
}
Method[] methods = c.getMethods();
// get all public method.
boolean hasMethod = hasMethods(methods);
// 在invokeMethod方法中新增try的程式碼
if (hasMethod) {
c3.append(" try{");
}
// 遍歷方法
for (Method m : methods) {
// 忽律Object的方法
if (m.getDeclaringClass() == Object.class) //ignore Object's method.
continue;
// 判斷方法名和方法引數長度
String mn = m.getName();
c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
// 方法引數長度
int len = m.getParameterTypes().length;
// 判斷方法引數長度程式碼
c3.append(" && ").append(" $3.length == ").append(len);
// 若相同方法名存在多個,增加引數型別陣列的比較判斷
boolean override = false;
for (Method m2 : methods) {
if (m != m2 && m.getName().equals(m2.getName())) {
override = true;
break;
}
}
if (override) {
if (len > 0) {
for (int l = 0; l < len; l++) {
c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
.append(m.getParameterTypes()[l].getName()).append("\")");
}
}
}
c3.append(" ) { ");
// 如果返回型別是void,則return null,如果不是,則返回對應引數型別
if (m.getReturnType() == Void.TYPE)
c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(),"$4")).append(");").append(" return null;");
else
c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(),"$4")).append(");");
c3.append(" }");
mns.add(mn);
if (m.getDeclaringClass() == c)
dmns.add(mn);
ms.put(ReflectUtils.getDesc(m),m);
}
if (hasMethod) {
c3.append(" } catch(Throwable e) { ");
c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
c3.append(" }");
}
c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
// 處理get set方法
// deal with get/set method.
Matcher matcher;
for (Map.Entry<String,Method> entry : ms.entrySet()) {
String md = entry.getKey();
Method method = (Method) entry.getValue();
if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn,method.getReturnType());
} else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn,method.getReturnType());
} else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
Class<?> pt = method.getParameterTypes()[0];
String pn = propertyName(matcher.group(1));
c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt,"$3")).append("); return; }");
pts.put(pn,pt);
}
}
c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
cc.setSuperClass(Wrapper.class);
// 增加無參構造器
cc.addDefaultConstructor();
// 新增屬性
cc.addField("public static String[] pns;"); // property name array.
cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
cc.addField("public static String[] mns;"); // all method name array.
cc.addField("public static String[] dmns;"); // declared method name array.
for (int i = 0,len = ms.size(); i < len; i++)
cc.addField("public static Class[] mts" + i + ";");
// 新增屬性相關的方法
cc.addMethod("public String[] getPropertyNames(){ return pns; }");
cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
cc.addMethod("public String[] getMethodNames(){ return mns; }");
cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
cc.addMethod(c1.toString());
cc.addMethod(c2.toString());
cc.addMethod(c3.toString());
try {
// 生成位元組碼
Class<?> wc = cc.toClass();
// setup static field.
// 反射,設定靜態變數的值
wc.getField("pts").set(null,pts);
wc.getField("pns").set(null,pts.keySet().toArray(new String[0]));
wc.getField("mns").set(null,mns.toArray(new String[0]));
wc.getField("dmns").set(null,dmns.toArray(new String[0]));
int ix = 0;
for (Method m : ms.values())
wc.getField("mts" + ix++).set(null,m.getParameterTypes());
// // 建立物件並且返回
return (Wrapper) wc.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(),e);
} finally {
cc.release();
ms.clear();
mns.clear();
dmns.clear();
}
}
複製程式碼
Wrapper是用於建立某個物件的方法呼叫的包裝器,利用位元組碼技術在呼叫方法時進行編譯相關方法。其中getWrapper就是獲得Wrapper 物件,其中關鍵的是makeWrapper方法,所以我在上面加上了makeWrapper方法的解釋,其中就是相關方法的位元組碼生成過程。
後記
該部分相關的原始碼解析地址:github.com/CrazyHZM/in…
該文章講解了遠端呼叫中關於代理的部分,關鍵部分在於基於javassist實現的位元組碼技術來支撐動態代理。接下來我將開始對rpc模組的dubbo-rpc-dubbo關於dubbo協議部分進行講解。