spring xml 標簽解析

2箱残、源碼
2.1求妹、入口
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions

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;
                    //循環(huán)遍歷節(jié)點,如果是默認命名空間雹熬,則采取默認元素解析方法宽菜,否則采用自定義元素解析方法
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

2.2、解析過程
BeanDefinitionParserDelegate.parseCustomElement

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        //獲取當前元素的命名空間
        String namespaceUri = getNamespaceURI(ele);
        if (namespaceUri == null) {
            return null;
        }
        //根據(jù)命名空間獲取對應Handler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        //通過返回的處理器解析當前元素
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

2.2.1竿报、獲取節(jié)點的命名空間
String namespaceUri = getNamespaceURI(ele);

2.2.2铅乡、根據(jù)命名空間獲取對應的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

this.readerContext.getNamespaceHandlerResolver();
此方法返回結(jié)果是NamespaceHandlerResolver,而NamespaceHandlerResolver的實現(xiàn)類是DefaultNamespaceHandlerResolver烈菌,進入到DefaultNamespaceHandlerResolver.resolve:

public NamespaceHandler resolve(String namespaceUri) {
        //獲取handlerMapping阵幸,即spring.handlers中存儲的信息花履,以 namespaceUri -> NamespaceHandler名字 的形式存儲
        //如果已經(jīng)實例化,則該namespaceUri對應的value值是NamespaceHandler對象挚赊,而不是String類型
        Map<String, Object> handlerMappings = getHandlerMappings();
        //獲取到對應的NamespaceHandler名字或者實例
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        //如果當前類已經(jīng)實例化臭挽,則直接返回
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        //還未實例化,則上面獲取的handlerOrClassName只是名字咬腕,還需實例化
        else {
            //獲取到className
            String className = (String) handlerOrClassName;
            try {
                //通過className以及當前類加載器加載class類
                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");
                }
                //實例化對應的Handler
                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                namespaceHandler.init();
                //將實例化好的Handler以namespaceUri->Handler的形式存儲在handlerMappings中
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
            catch (ClassNotFoundException ex) {
                throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
                        "] for namespace [" + namespaceUri + "]", ex);
            }
            catch (LinkageError err) {
                throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
                        className + "] for namespace [" + namespaceUri + "]", err);
            }
        }
    }

以上代碼一共做了這么幾件事:
1欢峰、讀取所有META-INF/spring.handlers的文件,并且以namespaceUri -> NamespaceHandler名字 的形式存儲
2涨共、根據(jù)傳入的namespaceUri獲取對應的值纽帖,如果該值類型是NamespaceHandler,則直接返回举反;如果是字符串類型懊直,則還未實例化,進行實例化火鼻,然后將實例化NamespaceHandler替代原來的NamespaceHandler名字
3室囊、返回對應的NamespaceHandler

2.2.3、解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

這句代碼的做了這么2件事:
1魁索、查找到對應的BeandefinitionParser
2融撞、解析
2.2.3.1、定位BeanDefinitionParser
首先我們可以得知當前NamespaceHandler為UserNamespaceHandler,那么要如何獲取到對應的UserBeanDefinitionParser粗蔚,首先我們知道UserNamespaceHandler有如下方法:

public class UserNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        //以節(jié)點本地名稱->BeanDefinitioinParser的形式存儲在Map<String, BeanDefinitionParser>中
        registerBeanDefinitionParser("user",new UserBeanDefinitionParse());
    }
}

由于UserNamespaceHandler繼承了NamespaceHandlerSupport尝偎,進入到NamespaceHandlerSupport:

public abstract class NamespaceHandlerSupport implements NamespaceHandler {
   /**
     * Stores the {@link BeanDefinitionParser} implementations keyed by the
     * local name of the {@link Element Elements} they handle.
     * 以節(jié)點本地名稱->BeanDefinitionParser的形式存儲于Map
     */
    private final Map<String, BeanDefinitionParser> parsers =
            new HashMap<String, BeanDefinitionParser>();
        
    /**
      * 將對應的BeanDefinitionParser存放到map中
      */
    protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
        this.parsers.put(elementName, parser);
    }
    
    //根據(jù)Element的localName定位到對應的BeanDefinitionParser
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        //獲取節(jié)點的本地名稱
        String localName = parserContext.getDelegate().getLocalName(element);
        //根據(jù)節(jié)點本地名稱獲取到對應BeanDefinitionParser
        BeanDefinitionParser parser = this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal(
                    "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        }
        return parser;
    }
}

因此,我們可以知道:
1鹏控、NamespaceHandler在初始化(init)時將對應的BeanDefinitionParser以elementName->BeanDefinitionParser的形式存儲在map中
2致扯、NamespaceHandler可以根據(jù)Element的localName,從而定位到對應的BeanDefinitionParser
2.2.3.2当辐、解析
由于當前定位到的解析器為UserBeanDefinitionParse抖僵,它的繼承體系圖如圖所示:
2.2.3.2.1、AbstractBeanDefinitionParser.parse

public final BeanDefinition parse(Element element, ParserContext parserContext) {
        //模板方法缘揪,由子類完成耍群,解析相應的標簽,除了id以及name以外
        AbstractBeanDefinition definition = parseInternal(element, parserContext);
        if (definition != null && !parserContext.isNested()) {
            try {
                //解析該標簽的id屬性
                String id = resolveId(element, definition, parserContext);
                if (!StringUtils.hasText(id)) {
                    parserContext.getReaderContext().error(
                            "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
                                    + "' when used as a top-level tag", element);
                }
                String[] aliases = null;
                if (shouldParseNameAsAliases()) {
                    String name = element.getAttribute(NAME_ATTRIBUTE);
                    if (StringUtils.hasLength(name)) {
                        aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                    }
                }
                //將id作為beanName寺晌,結(jié)合definition構(gòu)建BeanDefinitionHolder
                BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
                //以beanName->BeanDefinition的形式注冊BeanDefinition
                registerBeanDefinition(holder, parserContext.getRegistry());
                if (shouldFireEvents()) {
                    BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
                    postProcessComponentDefinition(componentDefinition);
                    parserContext.registerComponent(componentDefinition);
                }
            }
            catch (BeanDefinitionStoreException ex) {
                String msg = ex.getMessage();
                parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
                return null;
            }
        }
        return definition;
    }

這個方法主要做了這么幾件事:
1世吨、解析自定義標簽相關屬性parseInternal(element, parserContext);澡刹,此方法交由子類完成
2呻征、獲取節(jié)點的id屬性,并將其作為beanName
3罢浇、注冊BeanDefinition
由上面的類體系圖可以得知陆赋,AbstractSingleBeanDefinitionParser實現(xiàn)了parserInternal
2.2.3.2.2沐祷、AbstractSingleBeanDefinitionParser.parserInternal

protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        //構(gòu)建BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        //設置parnetName屬性
        String parentName = getParentName(element);
        if (parentName != null) {
            builder.getRawBeanDefinition().setParentName(parentName);
        }
        //設置beanClass
        Class<?> beanClass = getBeanClass(element);
        if (beanClass != null) {
            builder.getRawBeanDefinition().setBeanClass(beanClass);
        }
        else {
            String beanClassName = getBeanClassName(element);
            if (beanClassName != null) {
                builder.getRawBeanDefinition().setBeanClassName(beanClassName);
            }
        }
        builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
        BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
        if (containingBd != null) {
            // Inner bean definition must receive same scope as containing bean.
            builder.setScope(containingBd.getScope());
        }
        if (parserContext.isDefaultLazyInit()) {
            // Default-lazy-init applies to custom bean definitions as well.
            builder.setLazyInit(true);
        }
        //模板方法,交由子類實現(xiàn)
        doParse(element, parserContext, builder);
        return builder.getBeanDefinition();
    }

這個方法一共做了這么幾件事:
1攒岛、構(gòu)建BeanDefinition
2赖临、設置相關基本屬性
3、解析節(jié)點灾锯,由子類實現(xiàn)doParse
因此調(diào)用UserBeanDefinitionParse.doParse

2.2.3.2.3兢榨、最后調(diào)用具體實現(xiàn)類的doParse方法

protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String userName = element.getAttribute("userName");
        String password = element.getAttribute("password");
        if(StringUtils.hasText(userName)){
            builder.addPropertyValue("userName",userName);
        }
        if(StringUtils.hasText(password)){
            builder.addPropertyValue("password",password);
        }
    }

關于spring中<util:/>的配置

spring mvc 標簽解析

spring解析自定義標簽

DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
InterceptorsBeanDefinitionParser http://www.cnblogs.com/fangjian0423/p/springMVC-interceptor.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市顺饮,隨后出現(xiàn)的幾起案子拆讯,更是在濱河造成了極大的恐慌芯杀,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘿架,居然都是意外死亡,警方通過查閱死者的電腦和手機第队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門谦疾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人佃乘,你說我怎么就攤上這事囱井。” “怎么了趣避?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵琅绅,是天一觀的道長。 經(jīng)常有香客問我鹅巍,道長千扶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任骆捧,我火速辦了婚禮澎羞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敛苇。我一直安慰自己妆绞,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布枫攀。 她就那樣靜靜地躺著括饶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪来涨。 梳的紋絲不亂的頭發(fā)上图焰,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音蹦掐,去河邊找鬼技羔。 笑死僵闯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的藤滥。 我是一名探鬼主播鳖粟,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拙绊!你這毒婦竟也來了向图?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤标沪,失蹤者是張志新(化名)和其女友劉穎张漂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谨娜,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡航攒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趴梢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漠畜。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坞靶,靈堂內(nèi)的尸體忽然破棺而出憔狞,到底是詐尸還是另有隱情,我是刑警寧澤彰阴,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布瘾敢,位于F島的核電站,受9級特大地震影響尿这,放射性物質(zhì)發(fā)生泄漏簇抵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一射众、第九天 我趴在偏房一處隱蔽的房頂上張望碟摆。 院中可真熱鬧,春花似錦叨橱、人聲如沸典蜕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愉舔。三九已至,卻和暖如春伙菜,著一層夾襖步出監(jiān)牢的瞬間轩缤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留典奉,地道東北人躺翻。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓丧叽,卻偏偏與公主長得像卫玖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子踊淳,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

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