<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JavaSPI 機制學(xué)習(xí)筆記

          共 4529字,需瀏覽 10分鐘

           ·

          2021-02-17 12:18

          公眾號關(guān)注?“GitHub今日熱榜
          設(shè)為 “星標(biāo)”,帶你挖掘更多開發(fā)神器!






          最近在閱讀框架源代碼時,常??吹?SPI 的子包, 忍不住查了下:Service Provider Interface : 服務(wù)提供接口。


          JavaSPI 實際上是“基于接口的編程+策略模式+配置文件”組合實現(xiàn)的動態(tài)加載機制。具體而言:


          STEP1. 定義一組接口, 假設(shè)是 autocomplete.PrefixMatcher;

          ? ? ??

          STEP2. 寫出接口的一個或多個實現(xiàn)(autocomplete.EffectiveWordMatcher, autocomplete.SimpleWordMatcher);

          ? ? ??

          STEP3. 在 src/main/resources/ 下建立 /META-INF/services 目錄, 新增一個以接口命名的文件 autocomplete.PrefixMatcher, 內(nèi)容是要應(yīng)用的實現(xiàn)類(autocomplete.EffectiveWordMatcher 或 autocomplete.SimpleWordMatcher 或兩者);

          ? ? ??

          STEP4. 使用 ServiceLoader 來加載配置文件中指定的實現(xiàn)。?

            

          SPI 的應(yīng)用之一是可替換的插件機制。比如查看 JDBC 數(shù)據(jù)庫驅(qū)動包,mysql-connector-java-5.1.18.jar 就有一個 /META-INF/services/java.sql.Driver 里面內(nèi)容是 com.mysql.jdbc.Driver 。


          ? ?

          代碼示例:

            ?

          1. 編寫接口和實現(xiàn)類:autocomplete.PrefixMatcher, ?autocomplete.EffectiveWordMatcher, autocomplete.SimpleWordMatcher 見 《輸入自動提示與補全功能的設(shè)計與實現(xiàn)》;

            

          2. 在 src/main/resources/ 下建立文件 /META-INF/services/ autocomplete.PrefixMatcher 填入上述兩個類之一或兩者都填; 

            

          3. 編寫測試類。? ? ??


          package autocomplete;

          import?java.util.Iterator;
          import?java.util.ServiceLoader;

          /**
          ?* Created by lovesqcc on 16-2-29.
          ?*/

          public?class?PrefixMatcherTest {

          ????public?static?void?main(String[] args) {
          ????????ServiceLoader matcher = ServiceLoader.load(PrefixMatcher.class);
          ????????Iterator matcherIter = matcher.iterator();
          ????????while?(matcherIter.hasNext()) {
          ????????????PrefixMatcher wordMatcher = matcherIter.next();
          ????????????System.out.println(wordMatcher.getClass().getName());
          ????????????String[] prefixes = new?String[] {"a", "b", "c", "d", "e", "f", "g", "i",
          ????????????????????"l", "n", "p", "r", "s", "t", "v", "w", "do", "finally"};
          ????????????for?(String?prefix: prefixes) {
          ????????????????System.out.println(wordMatcher.obtainMatchedWords(prefix));
          ????????????}
          ????????}

          ????}
          }


          要寫個 ServiceLoader 的簡單實現(xiàn)也不難:1. 讀取配置文件,獲取實現(xiàn)類的全名稱字符串;2. 使用 Java 反射機制來構(gòu)造服務(wù)實現(xiàn)類的實例。可以使用泛型方法,避免獲取的時候做類型轉(zhuǎn)換。不過 JDK 自帶的 java.util.ServiceLoader 實現(xiàn)得更加嚴(yán)謹(jǐn)一些,使用了 ClassLoader 來加載類,并使用迭代器來獲取服務(wù)實現(xiàn)類。思路大體相同。


          package autocomplete;

          import?java.io.*;
          import?java.util.ArrayList;
          import?java.util.List;

          /**
          ?* Created by lovesqcc on 16-2-29.
          ?* A very Simple JavaSPI implementation using java reflection
          ?*/

          public?class?SimpleServiceLoader {

          ????private?static?final String?PREFIX = "/META-INF/services/";

          ????public?static? List load(Class cls) {
          ????????List<String> implClasses = readServiceFile(cls);
          ????????List implList = new?ArrayList();
          ????????for?(String?implClass : implClasses) {
          ????????????Class c = null;
          ????????????try?{
          ????????????????c = (Class) Class.forName(implClass);
          ????????????????implList.add(c.newInstance());
          ????????????} catch?(Exception e) {
          ????????????????return?new?ArrayList();
          ????????????}
          ????????}
          ????????return?implList;
          ????}

          ????private?static?List<String> readServiceFile(Class cls) {
          ????????String?infName = cls.getCanonicalName();
          ????????String?fileName = cls.getResource(PREFIX+infName).getPath();
          ????????try?{
          ????????????BufferedReader br = new?BufferedReader(new?FileReader(new?File(fileName)));
          ????????????String?line = "";
          ????????????List<String> implClasses = new?ArrayList<String>();
          ????????????while?((line = br.readLine()) != null) {
          ????????????????implClasses.add(line);
          ????????????}
          ????????????return?implClasses;
          ????????} catch?(FileNotFoundException fnfe) {
          ????????????System.out.println("File not found: "?+ fileName);
          ????????????return?new?ArrayList<String>();
          ????????} catch?(IOException ioe) {
          ????????????System.out.println("Read file failed: "?+ fileName);
          ????????????return?new?ArrayList<String>();
          ????????}
          ????}

          ????public?static?void?main(String[] args) {
          ????????List implList = load(PrefixMatcher.class);
          ????????if?(implList != null?&& implList.size() >0) {
          ????????????for?(PrefixMatcher matcher: implList) {
          ????????????????System.out.println(matcher.obtainMatchedWords("sh"));
          ????????????}
          ????????}
          ????}
          }


          ServiceLoader 的實現(xiàn)涉及到如下概念:指向?qū)ο箢愋偷? Class 對象;類加載器 ClassLoader;服務(wù)實現(xiàn)類的資源抽象;服務(wù)實現(xiàn)類的全名字符串。結(jié)合類加載器和資源抽象獲得服務(wù)實現(xiàn)類的全名字符串,再通過類加載器獲取 Class 對象, 最后通過 Class 對象來構(gòu)造服務(wù)實現(xiàn)類 S 的實例 s 。

          ServiceLoader 的實現(xiàn)主要包括:

          ? ? ??

          1. ?內(nèi)部成員包含providers, LazyIterator lookupIterator>。其中,service 是服務(wù)接口,loader 是類加載器, providers 是服務(wù)實現(xiàn)類的緩存, lookupIterator 是獲取服務(wù)實現(xiàn)類的迭代器,是 ServiceLoader 的內(nèi)部類;

          ? ? ??

          2. LazyIterator 的內(nèi)部成員包括configs, Iteratorpending, String nextName>。其中,configs 存放服務(wù)實現(xiàn)類的資源配置抽象, pending 存放服務(wù)實現(xiàn)類的全名字符串, nextName 是下一個可獲取的服務(wù)實現(xiàn)類的全名字符串。加載資源使用到 classLoader 的 getSystemResources 和 getResources 方法。Java里的資源抽象使用類 URL 來唯一標(biāo)識,無論是本地文件 ( file:/// ) 還是網(wǎng)絡(luò)文件 (http(s):// )。由于要從文件或網(wǎng)絡(luò)讀取文本字符串,因此要使用 BufferedReader 。

            

          在 Java 中,Class和 ClassLoader 是造物之始。萬物皆是“某類T” 的存在物,而“某類T” 是“萬類之類 Class” 的存在物,類別也是一種存在物,存在物即 Object。實例 t -> 類別 T -> 所有類別的抽象 Class-> Object。要創(chuàng)造類別 T 的實例,先通過某種方式(ClassLoader)找到該物的“種子”(Class對象),然后通過該種子來創(chuàng)造具體的物 t。要生成一個 Integer 對象,先找到 Class, 然后 newInstance 出 Integer 的實例。而造物也要有個規(guī)則,“女媧造物”和“凡人造物”,如果要造一模一樣的物種,必須先經(jīng)由女媧造物,否則就會造成混亂(至少軟件中會出現(xiàn)問題)。在 Java 里就有BootstrapClassLoader -> ExtClassLoader -> AppClassLoader -> CustomClassLoader 的先后規(guī)則。



          出處:cnblogs.com/lovesqcc/p/5229353.html








          關(guān)注GitHub今日熱榜,專注挖掘好用的開發(fā)工具,致力于分享優(yōu)質(zhì)高效的工具、資源、插件等,助力開發(fā)者成長!







          點個在看 你最好看









          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    亚洲女人天堂 | aaa国产精品 | 亚洲国产精品自拍 | 激情五月婷婷综合 | 久操伊人 |