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;
                    //循环遍历节点,如果是默认命名空间,则采取默认元素解析方法,否则采用自定义元素解析方法
                    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;
        }
        //根据命名空间获取对应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、获取节点的命名空间
String namespaceUri = getNamespaceURI(ele);

2.2.2、根据命名空间获取对应的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

this.readerContext.getNamespaceHandlerResolver();
此方法返回结果是NamespaceHandlerResolver,而NamespaceHandlerResolver的实现类是DefaultNamespaceHandlerResolver,进入到DefaultNamespaceHandlerResolver.resolve:

public NamespaceHandler resolve(String namespaceUri) {
        //获取handlerMapping,即spring.handlers中存储的信息,以 namespaceUri -> NamespaceHandler名字 的形式存储
        //如果已经实例化,则该namespaceUri对应的value值是NamespaceHandler对象,而不是String类型
        Map<String, Object> handlerMappings = getHandlerMappings();
        //获取到对应的NamespaceHandler名字或者实例
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        //如果当前类已经实例化,则直接返回
        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、根据传入的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() {
        //以节点本地名称->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.
     * 以节点本地名称->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);
    }
    
    //根据Element的localName定位到对应的BeanDefinitionParser
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        //获取节点的本地名称
        String localName = parserContext.getDelegate().getLocalName(element);
        //根据节点本地名称获取到对应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可以根据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,结合definition构建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、获取节点的id属性,并将其作为beanName
3、注册BeanDefinition
由上面的类体系图可以得知,AbstractSingleBeanDefinitionParser实现了parserInternal
2.2.3.2.2、AbstractSingleBeanDefinitionParser.parserInternal

protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        //构建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);
        }
        //模板方法,交由子类实现
        doParse(element, parserContext, builder);
        return builder.getBeanDefinition();
    }

这个方法一共做了这么几件事:
1、构建BeanDefinition
2、设置相关基本属性
3、解析节点,由子类实现doParse
因此调用UserBeanDefinitionParse.doParse

2.2.3.2.3、最后调用具体实现类的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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容