spring類的加載之META-INF/spring.handlers

一 spring之META-INF/spring.handlers
在springboot 項目中通常都有一個application.xml的配置文件善镰。
其中的配置解析一個核心步驟如下:

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();

            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element)node;
                    if (delegate.isDefaultNamespace(ele)) {
                       //<beans>標(biāo)簽
                        this.parseDefaultElement(ele, delegate);
                    } else {
                      //非<beans>標(biāo)簽
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }

進(jìn)入 delegate.parseCustomElement(ele)方法。在類BeanDefinitionParserDelegate中。

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = this.getNamespaceURI(ele);
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        } else {
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }
    }

其中bean定義都是交由NamespaceHandler 來解析。也就是說除了<beans>標(biāo)簽外所有的類定義的加載都會有一個對應(yīng)的NameSpaceHanlder來處理具體的BeanDefinition的獲取屋吨。
NamespaceHandler是一個接口:

public interface NamespaceHandler {
    void init();
    BeanDefinition parse(Element var1, ParserContext var2);

    BeanDefinitionHolder decorate(Node var1, BeanDefinitionHolder var2, ParserContext var3);
}

回到BeanDefinitionParserDelegate.parseCustomElement(ele)方法中门粪,這個方法主要分為三步驟
1.獲取一個namespaceUri,
2.根據(jù)namespaceUri獲取一個NamespaceHandler實例handler椰拒。

  1. 讓handler解析出我們想要的BeanDefinition.

先看如何獲取一個標(biāo)簽對應(yīng)的namespaceUri,以spring標(biāo)簽 <context:annotation-config/>為例凰荚。
我們的application.xml都會有形如

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
       default-lazy-init="false">

這樣的頭部
<context:annotation-config/> 對應(yīng)的namespaceUri即為對應(yīng)的http://www.springframework.org/schema/context

讓我們來到第二步handler的獲取燃观,在DefaultNamespaceHandlerResolver.resolve(String namespaceUri)方法中。

    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = this.getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;

            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                } else {
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                    namespaceHandler.init();
                    handlerMappings.put(namespaceUri, namespaceHandler);
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
            }
        }
    }

整個方法并不復(fù)雜便瑟,在解析整個方法之前缆毁,我們先看下該類的兩個構(gòu)造方法:

    public DefaultNamespaceHandlerResolver() {
        this((ClassLoader)null, "META-INF/spring.handlers");
    }
    public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
        this(classLoader, "META-INF/spring.handlers");
    }
    public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
        this.logger = LogFactory.getLog(this.getClass());
        Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
        this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
//  "META-INF/spring.handlers"     
 this.handlerMappingsLocation = handlerMappingsLocation;
    }

看到了嗎,這里終于出現(xiàn)了我們這篇文章的主角"META-INF/spring.handlers"到涂,spring默認(rèn)就是取這個路徑下的配置信息脊框。下面是spring-aop包下的META-INF/spring.handlers文件中的內(nèi)容

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

回到DefaultNamespaceHandlerResolver.resolve(String namespaceUri)方法。

  1. Map<String, Object> handlerMappings = this.getHandlerMappings();方法會返回所有的META-INF/spring.handlers中的所有的配置信息践啄,這個方法保存在實例屬性handlerMappings中浇雹,如若是第一次調(diào)用,會加載屿讽,后面的調(diào)用都是直接返回實例屬性handlerMappings昭灵。
  2. 后面的邏輯主要就是一個if --else if--else 結(jié)構(gòu)。 handlerMappings中一開始存放的都是對應(yīng)的namespaceHandler的全路徑名(String類型),如果是第一次獲取這個handler烂完,必然會走else分之试疙。
    這里也就是一個簡單的懶加載邏輯,因為并不是所有的META-INF/spring.handlers中的handler項目中都會用到窜护,所以也就沒必要實例化它們效斑,直到第一次調(diào)用的時候再去實例化。實例化邏輯不再具體分析柱徙。
    整個handler的獲取是很簡單的邏輯缓屠。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市护侮,隨后出現(xiàn)的幾起案子敌完,更是在濱河造成了極大的恐慌,老刑警劉巖羊初,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滨溉,死亡現(xiàn)場離奇詭異,居然都是意外死亡长赞,警方通過查閱死者的電腦和手機晦攒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來得哆,“玉大人脯颜,你說我怎么就攤上這事》肪荩” “怎么了栋操?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饱亮。 經(jīng)常有香客問我矾芙,道長,這世上最難降的妖魔是什么近上? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任剔宪,我火速辦了婚禮,結(jié)果婚禮上壹无,老公的妹妹穿的比我還像新娘葱绒。我一直安慰自己,他們只是感情好格遭,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著留瞳,像睡著了一般拒迅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天璧微,我揣著相機與錄音作箍,去河邊找鬼。 笑死前硫,一個胖子當(dāng)著我的面吹牛胞得,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屹电,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼阶剑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了危号?” 一聲冷哼從身側(cè)響起牧愁,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤燃逻,失蹤者是張志新(化名)和其女友劉穎蝙云,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體在旱,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡偷线,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年磨确,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片声邦。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡乏奥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出翔忽,到底是詐尸還是另有隱情英融,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布歇式,位于F島的核電站驶悟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏材失。R本人自食惡果不足惜痕鳍,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望龙巨。 院中可真熱鬧笼呆,春花似錦、人聲如沸旨别。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秸弛。三九已至铭若,卻和暖如春洪碳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叼屠。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工瞳腌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镜雨。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓嫂侍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荚坞。 傳聞我的和親對象是個殘疾皇子挑宠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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