欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程

程序员文章站 2022-12-25 12:48:18
原文出自: "http://cmsblogs.com" import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程。 在方法 中,如果遇到标签 为 bean 则调用 方法进行 bean 标签解析,如下: 整个过程分为四个步骤 1. 调用 进行元素解析,解析过 ......

原文出自:

import 标签解析完毕了,再看 spring 中最复杂也是最重要的标签 bean 标签的解析过程。

在方法 parsedefaultelement() 中,如果遇到标签 为 bean 则调用 processbeandefinition() 方法进行 bean 标签解析,如下:

    protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) {
        beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele);
        if (bdholder != null) {
            bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder);
            try {
                // register the final decorated instance.
                beandefinitionreaderutils.registerbeandefinition(bdholder, getreadercontext().getregistry());
            }
            catch (beandefinitionstoreexception ex) {
                getreadercontext().error("failed to register bean definition with name '" +
                        bdholder.getbeanname() + "'", ele, ex);
            }
            // send registration event.
            getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder));
        }
    }

整个过程分为四个步骤

  1. 调用 beandefinitionparserdelegate.parsebeandefinitionelement() 进行元素解析,解析过程中如果失败,返回 null,错误由 problemreporter 处理。如果解析成功则返回 beandefinitionholder 实例 bdholder。beandefinitionholder 为持有 name 和 alias 的 beandefinition。
  2. 若实例 bdholder 不为空,则调用 beandefinitionparserdelegate.decoratebeandefinitionifrequired() 进行自定义标签处理
  3. 解析完成后,则调用 beandefinitionreaderutils.registerbeandefinition() 对 bdholder 进行注册
  4. 发出响应事件,通知相关的监听器,完成 bean 标签解析

先看方法 parsebeandefinitionelement(),如下:

   public beandefinitionholder parsebeandefinitionelement(element ele, @nullable beandefinition containingbean) {
        // 解析 id 属性
        string id = ele.getattribute(id_attribute);
        // 解析 name 属性
        string nameattr = ele.getattribute(name_attribute);

        // 分割 name 属性
        list<string> aliases = new arraylist<>();
        if (stringutils.haslength(nameattr)) {
            string[] namearr = stringutils.tokenizetostringarray(nameattr, multi_value_attribute_delimiters);
            aliases.addall(arrays.aslist(namearr));
        }
    
        string beanname = id;
        if (!stringutils.hastext(beanname) && !aliases.isempty()) {
            beanname = aliases.remove(0);
            if (logger.isdebugenabled()) {
                logger.debug("no xml 'id' specified - using '" + beanname +
                        "' as bean name and " + aliases + " as aliases");
            }
        }
        
        // 检查 name 的唯一性
        if (containingbean == null) {
            checknameuniqueness(beanname, aliases, ele);
        }

        // 解析 属性,构造 abstractbeandefinition
        abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);
        if (beandefinition != null) {
            // 如果 beanname 不存在,则根据条件构造一个 beanname
            if (!stringutils.hastext(beanname)) {
                try {
                    if (containingbean != null) {
                        beanname = beandefinitionreaderutils.generatebeanname(
                                beandefinition, this.readercontext.getregistry(), true);
                    }
                    else {
                        beanname = this.readercontext.generatebeanname(beandefinition);
                        string beanclassname = beandefinition.getbeanclassname();
                        if (beanclassname != null &&
                                beanname.startswith(beanclassname) && beanname.length() > beanclassname.length() &&
                                !this.readercontext.getregistry().isbeannameinuse(beanclassname)) {
                            aliases.add(beanclassname);
                        }
                    }
                    if (logger.isdebugenabled()) {
                        logger.debug("neither xml 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanname + "]");
                    }
                }
                catch (exception ex) {
                    error(ex.getmessage(), ele);
                    return null;
                }
            }
            string[] aliasesarray = stringutils.tostringarray(aliases);
            
            // 封装 beandefinitionholder
            return new beandefinitionholder(beandefinition, beanname, aliasesarray);
        }

        return null;
    }

这个方法还没有对 bean 标签进行解析,只是在解析动作之前做了一些功能架构,主要的工作有:

  • 解析 id、name 属性,确定 alias 集合,检测 beanname 是否唯一
  • 调用方法 parsebeandefinitionelement() 对属性进行解析并封装成 genericbeandefinition 实例 beandefinition
  • 根据所获取的信息(beanname、aliases、beandefinition)构造 beandefinitionholder 实例对象并返回。

这里有必要说下 beanname 的命名规则:如果 id 不为空,则 beanname = id;如果 id 为空,但是 alias 不空,则 beanname 为 alias 的第一个元素,如果两者都为空,则根据默认规则来设置 beanname。

上面三个步骤第二个步骤为核心方法,它主要承担解析 bean 标签中所有的属性值。如下:

   public abstractbeandefinition parsebeandefinitionelement(
            element ele, string beanname, @nullable beandefinition containingbean) {

        this.parsestate.push(new beanentry(beanname));

        string classname = null;
        // 解析 class 属性
        if (ele.hasattribute(class_attribute)) {
            classname = ele.getattribute(class_attribute).trim();
        }
        string parent = null;

        // 解析 parent 属性
        if (ele.hasattribute(parent_attribute)) {
            parent = ele.getattribute(parent_attribute);
        }

        try {

            // 创建用于承载属性的 genericbeandefinition 实例
            abstractbeandefinition bd = createbeandefinition(classname, parent);

            // 解析默认 bean 的各种属性
            parsebeandefinitionattributes(ele, beanname, containingbean, bd);
            
            // 提取 description
            bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element));
            
            // 解析元数据
            parsemetaelements(ele, bd);
            
            // 解析 lookup-method 属性
            parselookupoverridesubelements(ele, bd.getmethodoverrides());
            
            // 解析 replaced-method 属性
            parsereplacedmethodsubelements(ele, bd.getmethodoverrides());
            
            // 解析构造函数参数
            parseconstructorargelements(ele, bd);
            
            // 解析 property 子元素
            parsepropertyelements(ele, bd);
            
            // 解析 qualifier 子元素
            parsequalifierelements(ele, bd);

            bd.setresource(this.readercontext.getresource());
            bd.setsource(extractsource(ele));

            return bd;
        }
        catch (classnotfoundexception ex) {
            error("bean class [" + classname + "] not found", ele, ex);
        }
        catch (noclassdeffounderror err) {
            error("class that bean class [" + classname + "] depends on not found", ele, err);
        }
        catch (throwable ex) {
            error("unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parsestate.pop();
        }

        return null;
    }

到这里,bean 标签的所有属性我们都可以看到其解析的过程,也就说到这里我们已经解析一个基本可用的 beandefinition。

由于解析过程较为漫长,篇幅较大,为了更好的观看体验,将这篇博文进行拆分。下篇博客主要介绍 beandefinition,以及解析默认 bean 的过程(parsebeandefinitionattributes()

--