摘要:的類繼承關系在實現中,默認使用進行動態編譯,不使用。那么這個是一個裝飾類還是一個動態代理類從上面的接口的定義并不能看出,跟進方法來看所以是一個裝飾類。
前面分析SPI機制時,提到createAdaptiveExtensionClass()自動生成和編譯一個動態的adpative類。
Compiler的類繼承關系:
在Dubbo實現中,默認使用JavassistCompiler進行動態編譯,不使用JdKComplier。這一點從Compiler接口的實現中可以看出。
@SPI("javassist") public interface Compiler { /** * Compile java source code. * * @param code Java source code * @param classLoader TODO * @return Compiled class */ Class> compile(String code, ClassLoader classLoader); }
可以看到,這里使用了@SPI注解,指定了使用javassist。
回顧前面的調用流程:
-->createAdaptiveExtensionClass() -->createAdaptiveExtensionClassCode() -->com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); -->compiler.compile(code, classLoader) -->AdaptiveCompiler.compile(code, classLoader) -->AbstractCompiler.compile(code, classLoader) -->Class> doCompile(String name, String source) -->JavassistCompiler.doCompile(String name, String source) -->cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());//編譯成class返回
根據前面分析SPI機制時得出的結論:
getExtensionLoader(Classtype) 就是為該接口new 一個ExtensionLoader,然后緩存起來。 getAdaptiveExtension() 獲取一個擴展類,如果@Adaptive注解在類上就是一個裝飾類;如果注解在方法上就是一個動態代理類,例如Protocol$Adaptive對象。 getExtension(String name) 獲取一個指定對象。
這里首先為Compiler接口創建了一個ExtensionLoader。然后調用getAdaptiveExtension()獲取擴展類。那么這個Compiler是一個裝飾類還是一個動態代理類?從上面的Compiler接口的定義并不能看出,跟進compile()方法來看:
@Adaptive public class AdaptiveCompiler implements Compiler
所以Compiler是一個裝飾類。
接著看createAdaptiveExtensionClass()具體實現:
private Class> createAdaptiveExtensionClass() { String code = createAdaptiveExtensionClassCode(); ClassLoader classLoader = findClassLoader(); com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
這里會執行到AdaptiveCompiler的實現:
@Adaptive public class AdaptiveCompiler implements Compiler { private static volatile String DEFAULT_COMPILER; public static void setDefaultCompiler(String compiler) { DEFAULT_COMPILER = compiler; } public Class> compile(String code, ClassLoader classLoader) { Compiler compiler; ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(Compiler.class); String name = DEFAULT_COMPILER; // copy reference if (name != null && name.length() > 0) { compiler = loader.getExtension(name); } else { compiler = loader.getDefaultExtension(); } return compiler.compile(code, classLoader); } }
這里DEFAULT_COMPILER執行compile時并未賦值,所以會執行else分支,這里最終會根據@SPI("javassist")獲取JavassistCompiler。然后使用其compile()進行編譯code,這里會調用到抽象類AbstractCompiler的實現:
public abstract class AbstractCompiler implements Compiler { private static final Pattern PACKAGE_PATTERN = Pattern.compile("packages+([$_a-zA-Z][$_a-zA-Z0-9.]*);"); private static final Pattern CLASS_PATTERN = Pattern.compile("classs+([$_a-zA-Z][$_a-zA-Z0-9]*)s+"); public Class> compile(String code, ClassLoader classLoader) { code = code.trim(); Matcher matcher = PACKAGE_PATTERN.matcher(code); String pkg; if (matcher.find()) { pkg = matcher.group(1); } else { pkg = ""; } matcher = CLASS_PATTERN.matcher(code); String cls; if (matcher.find()) { cls = matcher.group(1); } else { throw new IllegalArgumentException("No such class name in " + code); } String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls; try { return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass())); } catch (ClassNotFoundException e) { if (!code.endsWith("}")) { throw new IllegalStateException("The java code not endsWith "}", code: " + code + " "); } try { return doCompile(className, code); } catch (RuntimeException t) { throw t; } catch (Throwable t) { throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: " + code + " , stack: " + ClassUtils.toString(t)); } } } protected abstract Class> doCompile(String name, String source) throws Throwable; }
在上述代碼中首先會去使用類加載器Class.forName去加載目標類,如果類本身(如動態代理類$Adaptive)不存在則會走到異常處理代碼,doCompile()這里會調用到JavassistCompiler的具體實現。在該類中最后會返回編譯的class:
cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68531.html
摘要:如前所說,的目的是獲取一個指定實現類的對象。接下來從子模塊下的包的開始分析先來看這里繼承自類。如沒有擴展點,在擴展點實現調用該方法,并返回結果。前面已經分析過,就是使用讀取文件并緩存的反轉控制,就是從和里面提取對象賦值。 如前所說,Dubbo SPI的目的是獲取一個指定實現類的對象。那么Dubbo是通過什么方式獲取的呢?其實是調用ExtensionLoader.getExtension...
摘要:二注解該注解為了保證在內部調用具體實現的時候不是硬編碼來指定引用哪個實現,也就是為了適配一個接口的多種實現,這樣做符合模塊接口設計的可插拔原則,也增加了整個框架的靈活性,該注解也實現了擴展點自動裝配的特性。 Dubbo擴展機制SPI 前一篇文章《dubbo源碼解析(一)Hello,Dubbo》是對dubbo整個項目大體的介紹,而從這篇文章開始,我將會從源碼來解讀dubbo再各個模塊的實...
摘要:第二種是,是一款字節碼引擎工具,能夠在運行時編譯生成。后記該部分相關的源碼解析地址該文章講解了遠程調用中關于代理的部分,關鍵部分在于基于實現的字節碼技術來支撐動態代理。 遠程調用——Proxy 目標:介紹遠程調用代理的設計和實現,介紹dubbo-rpc-api中的各種proxy包的源碼。 前言 首先聲明叫做代理,代理在很多領域都存在,最形象的就是現在朋友圈的微商代理,廠家委托代理幫他們...
摘要:編譯完成后在目錄下有的包二部署首先將編譯后的包放到目錄,啟動。自動解壓包如圖是的一個應用服務器。也依賴填寫你的服務的部署地址。最后重啟,重啟之前保證服務處于運行狀態。 一.dubbo編譯1、先從github上下載dubbo源碼,地址:https://github.com/alibaba/du... showImg(https://segmentfault.com/img/bV1fir?...
閱讀 2137·2021-11-22 15:22
閱讀 1286·2021-11-11 16:54
閱讀 1807·2021-09-23 11:32
閱讀 3007·2021-09-22 10:02
閱讀 1771·2019-08-30 12:59
閱讀 1085·2019-08-29 16:27
閱讀 622·2019-08-29 13:21
閱讀 2464·2019-08-28 17:57