Spring IOC 之解析 bean 标签:开启解析进程,BeanDefinition

Spring IOC 之解析 bean 标签:开启解析进程,BeanDefinitionSpring IOC 之解析 bean 标签:开启解析进程,BeanDefinition

大家好,又见面了,我是你们的朋友全栈君。

在方法 parseDefaultElement() 中,如果遇到标签 为 bean 则调用 processBeanDefinition() 方法进行 bean 标签解析

整个过程分为四个步骤

  • 调用 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 进行元素解析,解析过程中如果失败,返回 null,错误由 ProblemReporter 处理。如果解析成功则返回 BeanDefinitionHolder 实例 bdHolder。BeanDefinitionHolder 为持有 name 和 alias 的 BeanDefinition。
  • 若实例 bdHolder 不为空,则调用 BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired() 进行自定义标签处理
  • 解析完成后,则调用 BeanDefinitionReaderUtils.registerBeanDefinition() 对 bdHolder 进行注册
  • 发出响应事件,通知相关的监听器,完成 Bean 标签解析

parseBeanDefinitionElement()

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

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

这里有必要说下 beanName 的命名规则:

  • 如果 id 不为空,则 beanName = id;
  • 如果 id 为空,但是 alias 不空,则 beanName 为 alias 的第一个元素,如果两者都为空,则根据默认规则来设置 beanName

BeanDefinition

  • 解析 bean 标签的过程其实就是构造一个 BeanDefinition 对象的过程
  • <bean> 元素标签拥有的配置属性,BeanDefinition 均提供了相应的属性,与之一一对应
  • 所以我们有必要对 BeanDefinition 有一个整体的认识

BeanDefinition 是一个接口,它描述了一个 Bean 实例

  • 包括属性值、构造方法值和继承自它的类的更多信息
  • 它继承 AttributeAccessor 和 BeanMetadataElement 接口
    • AttributeAccessor :定义了与其它对象的(元数据)进行连接和访问的约定,即对属性的修改,包括获取、设置、删除
    • BeanMetadataElement:Bean 元对象持有的配置元素可以通过getSource() 方法来获取

BeanDefinition 整个结构如下图:

    f30720e9703a84828c920db9570bbd69b02.jpg

  • 父 <bean> 用 RootBeanDefinition表示
  • 子 <bean> 用 ChildBeanDefinition 表示
  • 而没有父 <bean> 的就使用RootBeanDefinition 表示。GenericBeanDefinition 为一站式服务类
  • AbstractBeanDefinition对三个子类共同的类信息进行抽象。

解析 Bean 标签

  • 在 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 中完成 Bean 的解析
    • 返回的是一个已经完成对 <bean> 标签解析的 BeanDefinition 实例
    • 在该方法内部,首先调用 createBeanDefinition() 方法创建一个用于承载属性的 GenericBeanDefinition 实例
    • 委托 BeanDefinitionReaderUtils 创建

 

	protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
			throws ClassNotFoundException {
		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}
  • 创建完 GenericBeanDefinition 实例后,再调用 parseBeanDefinitionAttributes() 
  • 该方法将创建好的 GenericBeanDefinition 实例当做参数,对 Bean 标签的所有属性进行解析

完成 Bean 标签基本属性解析后

  • 会依次调用 parseMetaElements()、parseLookupOverrideSubElements()、parseReplacedMethodSubElements() 对子元素 meta、lookup-method、replace-method 完成解析

三个子元素的作用如下:

  • meta:元数据。
  • lookup-method:Spring 动态改变 bean 里方法的实现。方法执行返回的对象,使用 Spring 内原有的这类对象替换,通过改变方法返回值来动态改变方法。内部实现为使用 cglib 方法,重新生成子类,重写配置的方法和返回对象,达到动态改变的效果。
  • replace-method:Spring 动态改变 bean 里方法的实现。需要改变的方法,使用 Spring 内原有其他类(需要继承接口org.springframework.beans.factory.support.MethodReplacer)的逻辑,替换这个方法。通过改变方法执行逻辑来动态改变方法。

meta 子元素

  • meta :元数据。当需要使用里面的信息时可以通过key获取
  • meta 所声明的 key 并不会在 Bean 中体现,只是一个额外的声明,当我们需要使用里面的信息时,通过 BeanDefinition 的 getAttribute()
  • 解析过程较为简单,获取相应的 key – value 构建 BeanMetadataAttribute 对象,然后通过 addMetadataAttribute() 加入到 AbstractBeanDefinition

委托 AttributeAccessorSupport 实现

  • AttributeAccessorSupport 是接口 AttributeAccessor 的实现者
  • AttributeAccessor 接口定义了与其他对象的元数据进行连接和访问的约定,可以通过该接口对属性进行获取、设置、删除操作

lookup-method 子元素

  • lookup-method :获取器注入,是把一个方法声明为返回某种类型的 bean 但实际要返回的 bean 是在配置文件里面配置的
  • 该方法可以用于设计一些可插拔的功能上,解除程序依赖

举个栗子:

ef5a49854371c22ba0da9f4f1f848747684.jpg

  • 配置如下

75e68c1a323f31ee6c96276a39c98c16e4c.jpg

replace-method 子元素

  • replaced-method :可以在运行时调用新的方法替换现有的方法,还能动态的更新原有方法的逻辑
  • 该标签使用方法和 lookup-method 标签差不多,只不过替代方法的类需要实现 MethodReplacer 接口

举个栗子:

3b4c7a417d7e62727039346890bb76c7b45.jpg

  • 配置如下(执行原始方法):

8db291580b451f9a99ed4b1b6d92a474ee4.jpg

  • 配置如下(执行替换方法):

123dad2aecda5a12af18c4f5b3d7133b304.jpg

constructor-arg 子元素

29dad20d991fb118c304b1c6541c67b4deb.jpg

  • 首先获取 index、type、name 三个属性值,然后根据是否存在 index 来区分
  • 其实两者逻辑都差不多,总共分为如下几个步骤(以有 index 为例)
    • 构造 ConstructorArgumentEntry 对象并将其加入到 ParseState 队列中。ConstructorArgumentEntry 表示构造函数的参数
    • 调用 parsePropertyValue() 解析 constructor-arg 子元素,返回结果值
    • 根据解析的结果值构造 ConstructorArgumentValues.ValueHolder 实例对象
    • 将 type、name 封装到 ConstructorArgumentValues.ValueHolder 中,然后将 ValueHolder 实例对象添加到 indexedArgumentValues 中

parsePropertyValue() 对子元素进一步解析

  1. 提取 constructor-arg 子元素的 ref 和 value 的属性值,对其进行判断,以下两种情况是不允许存在的
    • ref 和 value 属性同时存在
    • 存在 ref 或者 value 且又有子元素
  2. 若存在 ref 属性,则获取其值并将其封装进 RuntimeBeanReference 实例对象中
  3. 若存在 value 属性,则获取其值并将其封装进 TypedStringValue 实例对象中
  4. 如果子元素不为空,则调用 parsePropertySubElement() 进行子元素进一步处理

需要调用 parsePropertySubElement() 进一步处理

property 子元素

a45424a08bbae59b899921a2522a6264c5f.jpg

Spring 调用 parsePropertyElements() 

转载于:https://my.oschina.net/u/3847203/blog/2250724

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107243.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java怎样编写程序_makefile编写实例

    java怎样编写程序_makefile编写实例最近准备花费很长一段时间写一些关于Java的从入门到进阶再到项目开发的教程,希望对初学Java的朋友们有所帮助,更快的融入Java的学习之中。主要内容包括JavaSE、JavaEE的基础知识以及如何

    2022年8月4日
    6
  • 实现安全登录的两种方法

    实现安全登录的两种方法登录安全——拦截器和过滤器或权限框架的使用本次我们将采用两种方法实现登录的安全性,首先介绍拦截器和过滤器。一、 过滤器和拦截器:过滤器产生的时间/开始工作的时间:进入Tomcat之后,但是在进servlet之前。Interceptor进入了servlet所以拦截器拦截的是动作,而过滤器拦截的是不合理的跳转页面。1、配置和使用拦截器。<mvc:interceptors>&…

    2022年4月19日
    48
  • 计组_浮点数表示/补码运算:定点数加减法/浮点数加减法(步骤+实例)「建议收藏」

    计组_浮点数表示/补码运算:定点数加减法/浮点数加减法(步骤+实例)「建议收藏」文章目录步骤问题实例对阶操作(基于补码)尾数求和(基于对阶后)规格化数相关知识左归操作右归操作回到本例:步骤设两个浮点数x=Sx⋅rjxy=Sy⋅rjy\begin{array}{l}x=S_{x}\cdotr^{j_{x}}\\y=S_{y}\cdotr^{j_{y}}\end{array}x=Sx​⋅rjx​y=Sy​⋅rjy​​(1)对阶,使两数的小数点位置对齐。(2)尾数求和,将对阶后的两尾数按定点加减运算规则求和(差)(3)规格化,为增加有效数字的位数,提高运

    2022年9月16日
    3
  • Ubuntu9.04上看电影加载中文字幕乱码问题

    Ubuntu9.04上看电影加载中文字幕乱码问题最近在我的Ubuntu9.04上看电影总是加载中文字幕的时候出现乱码,后来发现是字符编码的问题,今天休假在家就写了一个小的字符转码的程序,目前来说满足我自己的需求了,代码如下:importsys,ioiflen(sys.argv)!=2: print”Pleaseinputfilepath!”else: f1=io.open(sys.argv[1],”r”

    2022年7月11日
    20
  • 应用程序发生异常0xc0000095_0xc0000142

    应用程序发生异常0xc0000095_0xc0000142Hi,Imadeanexewhichisforsystemtray,thisexetogetsystemeventnotificationas(logoff&Shutdown)..itsworkingfinefor1-2hoursbutafterthatthisexeisgoingtocrashIamunable…

    2022年9月28日
    5
  • WebApp开发-Google官方教程

    WebApp开发-Google官方教程概览你可以使用viewport的元数据、CSS和Javascript来为不同分辨率的屏幕设置合适的页面本文档中的技术适用于Android 2.0及以上设备,针对默认的Android Browser中及在WebView中呈现的页面如果你在为Android开发Web应用或者在为移动设备重新设计一个Web应用,你需要仔细考虑在不同设备上你的页面看起来是怎样的。因为Android设备有不同款型

    2022年6月17日
    37

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号