<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## Java SPI SPI的全名為Service Provider Interface, java spi就是提供這樣的一個機制:為某個接口尋找服務實現的機制。有點類似IOC的思想,就是將裝配的控制權移到程序之外,在模塊化設計中這個機制尤其重要。 SPI的使用是尋找服務實現,例如,我們在項目A中定義了接口Developer,之后可以使用ServiceLoader加載Developer的實現類,實現類可能有B項目或C項目實現。 A項目: ``` package com.shisj.study.dubbo.spi.Developer; public interface Developer { public String getPrograme(); } ``` B項目中提供了兩種實現類: ``` package com.shisj.study.dubbo.spi.impl; public class JavaDeveloper implements Developer{ public String getPrograme() { return "Java"; } } ``` ``` package com.shisj.study.dubbo.spi.impl; public class PythonDeveloper implements Developer{ public String getPrograme() { return "Python"; } } ``` 在B項目的classpath下創建META-INF/services文件夾,內部包含com.shisj.study.dubbo.spi.Developer 文件,這是接口的全名。里面的內容是該借接口的實現類; ``` com.shisj.study.dubbo.spi.impl.JavaDeveloper com.shisj.study.dubbo.spi.impl.PythonDeveloper ``` 將B項目打包成jar包并引用至A項目中,然后我們就可以通過ServiceLoader查找實現類, ``` public ServiceLoader<Developer> serviceloader = ServiceLoader.load(Developer.class); for (Developer dev : serviceloader) { System.out.println("out." + dev.getPrograme()); } // out.Java // out.Python ``` ## Dubbo擴展 dubbo擴展點加載從JDK標準的SPI(Service Provider Interface)擴展點發現機制加強而來。具體的配置文件在classpath的/META-INF/dubbo/internal文件夾里面。dubbo的擴展機制與spi不同,其文件中的內容記錄了`key=class`,原因是: >當擴展點的static字段或方法簽名上引用了三方庫, 如果三方庫不存在,會導致類初始化失敗, Extension標識Dubbo就拿不到了,異常信息就和配置對應不起來。 比如: Extension("mina")加載失敗, 當用戶配置使用mina時,就會報找不到擴展點, 而不是報加載擴展點失敗,以及失敗原因。 ### ExtensionLoader 在dubbo源碼中,對可擴展點的加載都是通過ExtensionLoader類獲取實例的,例如: ``` // 獲取Compiler接口的實現類 ExtensionLoader<Compiler> loader1 = ExtensionLoader.getExtensionLoader(Compiler.class); Compiler compile1 = loader1.getAdaptiveExtension(); System.out.println(compile1.getClass()); Compiler compile2 = loader1.getExtension("jdk"); System.out.println(compile2.getClass()); ``` 這樣做的目的是擴展性強,使用者可以無侵入的方式自己進行實現接口供dubbo使用。 ExtensionLoader類內部保存著所有接口的實現類,并記錄了缺省Adaptive實現類和缺省的擴展類,我們可以通過屬性大致了解ExtensionLoader的功能。下面是實例屬性: ``` private final Class<?> type; // ExtensionLoader 創建時指定的類型 private final ExtensionFactory objectFactory; // ExtensionLoader的擴展工廠 private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>(); // 記錄了實現類的class與名稱的對應關系 private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();// 保存map,內部保存了實現類name與實現類class的對應關系 private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>(); //保存有@Activate注解的實現類 private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>(); //保存實現類name與實例 private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>(); //缺省的實例 private volatile Class<?> cachedAdaptiveClass = null; // 缺省的實現類 private String cachedDefaultName; // 默認的實現類名稱,@SPI中指定 private volatile Throwable createAdaptiveInstanceError; // 創建是的錯誤 private Set<Class<?>> cachedWrapperClasses; private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>(); ``` 除此之外,ExtensionLoader類內部的靜態屬性保存所有擴展類與ExtensionLoader、實例的映射。 ``` private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>(); ``` **加載過程** 首先根據class從EXTENSION_LOADERS查找對應的ExtensionLoader,如果為null則創建一個ExtensionLoader,指定其type為要查找的class。此時雖然獲取了ExtensionLoader,但還未查找接口的實現類,調用getExtension()或getAdaptiveExtension()等方法時才會真正的查找;getExtensionClasses()方法會依次查找下面3個路徑的文件,讀取內容獲得`name=class`鍵值對,并保存到相應的屬性中。 ``` META-INF/services/ META-INF/dubbo/ META-INF/dubbo/internal/ ``` 下面是解析文件并保存的過程: * cachedDefaultName 如果ExtensionLoader的type有SPI注解且設置了value,那么這個value就是該接口默認的實現類名稱cachedDefaultName,例如`Compiler`接口使用了注解`@SPI("javassist")`,那么Compiler的ExtensionLoader的cachedDefaultName為javassist。cachedDefaultName的目的是getDefaultExtension()獲取默認的實現類,或查找不到@Adaptiv的實現類時,使用cachedDefaultName創建Adaptive的實現類。 * 按照順序從3個文件夾中,讀取以type的全名命名的文件,解析name和class,如果實現類有@Adaptive注解,設置cachedAdaptiveClass為該實現類; * 如果沒有@Adaptive,首先判斷實現類是否有將要查找的接口作為參數的構造方法,如果有添加到cachedWrapperClasses變量中, * 如果沒有這種構造方法,判斷是否有@Activate注解,有的話保存到cachedActivates中;cachedNames保存所有的class和name的映射關系 * 最終,將name與實現類class的映射保存在cachedClasses中。 至此,ExtensionLoader針對給的的接口,查找了所有的擴展,并取得了默認實現類的名稱,Adaptive實現類class(可能沒有,后續獲取是dubbo會創建),以及name與實現類class的映射關系。 有了這些信息,在createExtension(name)時就會根據name獲得class然后newInstance獲取實例。 ## dubbo擴展測試 我們自己實現一個MyCompiler,其實現了Compiler接口 ``` public class MyCompiler implements Compiler { public Class<?> compile(String code, ClassLoader classLoader) { return new JavassistCompiler().compile(code, classLoader); } } ``` 在/META-INF/services/com.alibaba.dubbo.common.compiler.Compiler文件中加入下面的映射 ``` mycp=com.shisj.study.dubbo.loader.MyCompiler ``` 測試中,可以通過mycp獲取到實現類MyCompiler ``` Compiler compile2 = loader1.getExtension("mycp"); System.out.println(compile2.getClass());//class com.shisj.study.dubbo.loader.MyCompiler ``` **getAdaptiveExtension內部邏輯** getAdaptiveExtension首先會查找接口具有@Adaptive注解的實現類作為Adaptive類,如果沒有dubbo會動態創建一個新的類,內部會從url取參數,如果沒有則取默認的值,來自于接口的@SPI注解,如`@SPI("javassist")`的值。 **getExtension()** 獲得Adaptive類的實例后,會將其傳入cachedWrapperClasses,包裝為Wrapper類
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看