摘要:第二種是,是一款字節碼引擎工具,能夠在運行時編譯生成。后記該部分相關的源碼解析地址該文章講解了遠程調用中關于代理的部分,關鍵部分在于基于實現的字節碼技術來支撐動態代理。
遠程調用——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 publicT getProxy(Invoker invoker) throws RpcException { return getProxy(invoker, false); } @Override public T getProxy(Invoker 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, 0, len); interfaces[len] = GenericService.class; } // 獲得代理 return getProxy(invoker, interfaces); } public abstract T getProxy(Invoker 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
該類實現了本地存根的邏輯,關于本地存根的概念和使用在官方文檔中都有詳細說明。
地址:http://dubbo.apache.org/zh-cn...
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 publicT getProxy(Invoker invoker, boolean generic) throws RpcException { return proxyFactory.getProxy(invoker, generic); } @Override @SuppressWarnings({"unchecked", "rawtypes"}) public T getProxy(Invoker 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 Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { return proxyFactory.getInvoker(proxy, type, url); } private Exporter export(T instance, Class type, URL url) { return protocol.export(proxyFactory.getInvoker(instance, type, url)); }
該類里面最重要的就是getProxy方法的實現,在該方法中先根據配置生成加載stub服務類,然后通過構造方法將代理的對象進行包裝,最后暴露該服務,然后返回代理類對象。
(五)JdkProxyFactory該類繼承了AbstractProxyFactory,是jdk的代理工廠的主要邏輯。
public class JdkProxyFactory extends AbstractProxyFactory { @Override @SuppressWarnings("unchecked") publicT getProxy(Invoker invoker, Class>[] interfaces) { // 調用了 Proxy.newProxyInstance直接獲得代理類 return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker)); } @Override public Invoker getInvoker(T proxy, Class type, URL url) { // 創建AbstractProxyInvoker對象 return new AbstractProxyInvoker (proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, 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") publicT getProxy(Invoker invoker, Class>[] interfaces) { // 創建代理 return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } @Override public Invoker getInvoker(T proxy, Class type, 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 (proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class>[] parameterTypes, 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. Mapcache; synchronized (ProxyCacheMap) { // 通過類加載器獲得緩存 cache = ProxyCacheMap.get(cl); if (cache == null) { cache = new HashMap (); 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 worked = new HashSet (); List methods = new ArrayList (); 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)); 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#getWrapperpublic 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, String n, 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, String n, 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> pts = new HashMap >(); // Map ms = new LinkedHashMap (); // List mns = new ArrayList (); // method names. List dmns = new ArrayList (); // 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 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方法的解釋,其中就是相關方法的字節碼生成過程。
后記該部分相關的源碼解析地址:https://github.com/CrazyHZM/i...
該文章講解了遠程調用中關于代理的部分,關鍵部分在于基于javassist實現的字節碼技術來支撐動態代理。接下來我將開始對rpc模塊的dubbo-rpc-dubbo關于dubbo協議部分進行講解。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73008.html
摘要:而存在的意義就是保證請求或響應對象可在線程池中被解碼,解碼完成后,就會分發到的。 2.7大揭秘——服務端處理請求過程 目標:從源碼的角度分析服務端接收到請求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費端發送請求的過程,該篇就要將服務端處理請求的過程。也就是當服務端收到請求數據包后的一系列處理以及如何返回最終結果。我們也知道消費端在發送請求的時候已經做了編碼,所以我...
摘要:大揭秘異步化改造目標從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發送請求過程講到的十四的,在以前的邏輯會直接在方法中根據配置區分同步異步單向調用。改為關于可以參考源碼解析十遠程通信層的六。 2.7大揭秘——異步化改造 目標:從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協議,關于協議的系列可以查看下面的文章: du...
摘要:服務引用過程目標從源碼的角度分析服務引用過程。并保留服務提供者的部分配置,比如版本,,時間戳等最后將合并后的配置設置為查詢字符串中。的可以參考源碼解析二十三遠程調用的一的源碼分析。 dubbo服務引用過程 目標:從源碼的角度分析服務引用過程。 前言 前面服務暴露過程的文章講解到,服務引用有兩種方式,一種就是直連,也就是直接指定服務的地址來進行引用,這種方式更多的時候被用來做服務測試,不...
摘要:可以參考源碼解析二十四遠程調用協議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠程通信層的四。二十的可以參考源碼解析十七遠程通信的一。 2.7大揭秘——消費端發送請求過程 目標:從源碼的角度分析一個服務方法調用經歷怎么樣的磨難以后到達服務端。 前言 前一篇文章講到的是引用服務的過程,引用服務無非就是創建出一個代理。供消費者調用服務的相關方法。...
摘要:大揭秘目標了解的新特性,以及版本升級的引導。四元數據改造我們知道以前的版本只有注冊中心,注冊中心的有數十個的鍵值對,包含了一個服務所有的元數據。 DUBBO——2.7大揭秘 目標:了解2.7的新特性,以及版本升級的引導。 前言 我們知道Dubbo在2011年開源,停止更新了一段時間。在2017 年 9 月 7 日,Dubbo 悄悄的在 GitHub 發布了 2.5.4 版本。隨后,版本...
閱讀 2344·2021-11-23 09:51
閱讀 1999·2021-10-14 09:43
閱讀 2760·2021-09-27 13:35
閱讀 1144·2021-09-22 15:54
閱讀 2495·2021-09-13 10:36
閱讀 3785·2019-08-30 15:56
閱讀 3404·2019-08-30 14:09
閱讀 1711·2019-08-30 12:57