【死磕 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)); } }
整个过程分为四个步骤
- 调用
beandefinitionparserdelegate.parsebeandefinitionelement()
进行元素解析,解析过程中如果失败,返回 null,错误由problemreporter
处理。如果解析成功则返回 beandefinitionholder 实例 bdholder。beandefinitionholder 为持有 name 和 alias 的 beandefinition。 - 若实例 bdholder 不为空,则调用
beandefinitionparserdelegate.decoratebeandefinitionifrequired()
进行自定义标签处理 - 解析完成后,则调用
beandefinitionreaderutils.registerbeandefinition()
对 bdholder 进行注册 - 发出响应事件,通知相关的监听器,完成 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()
)
--
下一篇: php实现用于删除整个目录的递归函数