ServiceLoader整理

ServiceLoader整理

  • ServiceLoader簡單使用
    Search search = null; ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class); Iterator<Search> searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); }

  • 源碼分析

    • ServiceLoader.load
      • public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
        }
        public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
        {
        return new ServiceLoader<>(service, loader);
        }
        private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = svc;
        loader = cl;
        reload();
        }
        public void reload() {
        providers.clear();//private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
        lookupIterator = new LazyIterator(service, loader);
        }
        private class LazyIterator implements Iterator<S>//這里叫l(wèi)azy其實(shí)就是調(diào)用hasNext的時(shí)候才去加載
        {
        ...
        private LazyIterator(Class<S> service, ClassLoader loader) {
        this.service = service;
        this.loader = loader;
        }
        ...
        }
    • iterator()
      • public Iterator<S> iterator() {
          return new Iterator<S>() {//返回匿名內(nèi)部類
              Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();//目前這個(gè)linkedhashmap還是空的
              public boolean hasNext() {
                  if (knownProviders.hasNext())
                      return true;
                  return lookupIterator.hasNext();//knownProviders空時(shí)走這個(gè)
              }
              public S next() {
                  if (knownProviders.hasNext())
                      return knownProviders.next().getValue();
                  return lookupIterator.next();
              }
              public void remove() {
                  throw new UnsupportedOperationException();
              }
          };
        
        }
    • hasNext()
      • public boolean hasNext() {
        if (nextName != null) {//null 調(diào)用next后會置nextName為null,不調(diào)用next則nextName始終不為null
        return true;
        }
        if (configs == null) {//null
        try {
        String fullName = PREFIX + service.getName();
        if (loader == null)//null
        configs = ClassLoader.getSystemResources(fullName);
        else
        //這里加載資源: META-INF/services/packageName.className
        //Finds all the resources with the given name.
        //A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.
        configs = loader.getResources(fullName);
        } catch (IOException x) {
        fail(service, "Error locating configuration files", x);
        }
        }
        while ((pending == null) || !pending.hasNext()) {//null
        if (!configs.hasMoreElements()) {
        return false;
        }
        pending = parse(service, configs.nextElement());//go here
        }
        nextName = pending.next();// Iterator<String> pending
        return true;
        }
      • private Iterator<String> parse(Class service, URL u)throws ServiceConfigurationError
        {
        InputStream in = null;
        BufferedReader r = null;
        ArrayList<String> names = new ArrayList<>();
        try {
        in = u.openStream();
        r = new BufferedReader(new InputStreamReader(in, "utf-8"));
        int lc = 1;
        while ((lc = parseLine(service, u, r, lc, names)) >= 0);
        } catch (IOException x) {
        fail(service, "Error reading configuration file", x);
        } finally {
        try {
        if (r != null) r.close();
        if (in != null) in.close();
        } catch (IOException y) {
        fail(service, "Error closing configuration file", y);
        }
        }
        return names.iterator();
        }
    • next()
      • public S next() {
        if (!hasNext()) {
        throw new NoSuchElementException();
        }
        String cn = nextName;
        nextName = null;// *** 置nextName為null ***
        Class<?> c = null;
        try {
        c = Class.forName(cn, false, loader);
        } catch (ClassNotFoundException x) {
        fail(service, "Provider " + cn + " not found");
        }
        if (!service.isAssignableFrom(c)) {
        fail(service, "Provider " + cn + " not a subtype");
        }
        try {
        S p = service.cast(c.newInstance());// Casts an object to the class or interface represented by this Class object
        providers.put(cn, p);// add cache 放入到knownProviders里面
        return p;
        } catch (Throwable x) {
        fail(service, "Provider " + cn + " could not be instantiated: " + x, x);
        }
        throw new Error();// This cannot happen
        }
    • 小結(jié)
      • hasNext和next必須搭配一起使用
        • hasNext獲取nextName從一個(gè)Iterator<String>的pending中
        • next則拿這個(gè)nextName去加載創(chuàng)建Class并創(chuàng)建對象返回
      • 首次從lookupIterator中獲取,后面從knownProviders緩存里面獲取
  • References

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泻帮,更是在濱河造成了極大的恐慌麻养,老刑警劉巖拟淮,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扫茅,死亡現(xiàn)場離奇詭異砌些,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锦茁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叉存,“玉大人码俩,你說我怎么就攤上這事〖吣螅” “怎么了稿存?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵笨篷,是天一觀的道長。 經(jīng)常有香客問我瓣履,道長率翅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任袖迎,我火速辦了婚禮冕臭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘燕锥。我一直安慰自己辜贵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布脯宿。 她就那樣靜靜地躺著念颈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪连霉。 梳的紋絲不亂的頭發(fā)上榴芳,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機(jī)與錄音跺撼,去河邊找鬼窟感。 笑死,一個(gè)胖子當(dāng)著我的面吹牛歉井,可吹牛的內(nèi)容都是我干的柿祈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼哩至,長吁一口氣:“原來是場噩夢啊……” “哼躏嚎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起菩貌,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卢佣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箭阶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虚茶,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年仇参,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嘹叫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诈乒,死狀恐怖罩扇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怕磨,我是刑警寧澤暮蹂,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布寞缝,位于F島的核電站,受9級特大地震影響仰泻,放射性物質(zhì)發(fā)生泄漏荆陆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一集侯、第九天 我趴在偏房一處隱蔽的房頂上張望被啼。 院中可真熱鬧,春花似錦棠枉、人聲如沸浓体。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽命浴。三九已至,卻和暖如春贱除,著一層夾襖步出監(jiān)牢的瞬間生闲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工月幌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碍讯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓扯躺,卻偏偏與公主長得像捉兴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子录语,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法倍啥,類相關(guān)的語法,內(nèi)部類的語法澎埠,繼承相關(guān)的語法虽缕,異常的語法,線程的語...
    子非魚_t_閱讀 31,662評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理失暂,服務(wù)發(fā)現(xiàn),斷路器鳄虱,智...
    卡卡羅2017閱讀 134,697評論 18 139
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)弟塞。 張土汪:刷leetcod...
    土汪閱讀 12,748評論 0 33
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,814評論 0 11
  • 一首老歌,在你我揮手說再見的舊址拙已,安靜地跌落决记。 ——楔子 天涯逢秋,蒼茶漸染倍踪! 日月呼嘯系宫,旋轉(zhuǎn)得倉促索昂,注定了: 一...
    玨詩閱讀 383評論 0 0