栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

第四篇 再读Spring 之BeanDefinition注册

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

第四篇 再读Spring 之BeanDefinition注册

文章目录
  • 前言
  • 一、管理的必要性
    • 框架设计
    • 工程实现
  • 二、Spring的实现
    • 1.抽象接口BeanDefinitionRegistry
    • 2. 具体实现DefaultListableBeanFactory
  • 三、特色方法
    • removeBeanDefinition
    • BeanDefinitionOverriding
  • 总结


前言

前面几篇文章中,我们梳理了BeanDefinition相关的Resource、Resource加载、基于XML文件的BeanDefinition不同颗粒度解析,和XML中自定义标签解析。接下来,看看BeanDefinition的注册。

在开始之前,先回顾下BeanDefinition。BeanDefinition是Bean的相关定义。对一个具体的BeanDefinition,对内包含BeanDefinition对应的class,scope,init-method,destory-method等等,对外包含对其他BeanDefinition的关联关系,包括依赖和继承。
到这里,咱们讨论的是单个BeanDefinition。实际工程中,Bean有多个,对应的BeanDefinition也不止一个。于是灵魂拷问来了,要不要管理,如何管理?

所以,本文先YY下BeanDefinition管理的必要性,再看BeanFactory是怎么管理的,最后仔细看下Spring作者在操刀时加入的个人思想。


一、管理的必要性 框架设计

BeanDefinition对象是一类关键对象。主要体现在依赖关系复杂。依赖关系包括非BeanDefinition对BeanDefinition的依赖,以及BeanDefinition之间的依赖,就像中年人上有老,下有小同时还得照顾亲戚。依赖关系复杂,直接体现就是对象构造过程比较曲折,简单说不能 new XXBeanDefinition() 就完事了。

工程实现

由于存在依赖,也需要快速寻找依赖,很自然就想到通过集合集中管理,比如使用Map集合。Spring中也确实是这么干的。于是就需要一个Map集合+写入/获取方法。于是就YY出来了一个BeanDefinitionFactory(实际上是不存在的)接口,提供一个写入和获取方法。具体实现类内部通过Map集合实现读写。

二、Spring的实现 1.抽象接口BeanDefinitionRegistry

Spring首先定义了BeanDefinitionRegistry,提供了读写的方法。这个基本上和我们的想法是

代码如下:

public interface BeanDefinitionRegistry extends AliasRegistry {

	
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	
	boolean containsBeanDefinition(String beanName);

	
	String[] getBeanDefinitionNames();

	
	int getBeanDefinitionCount();

	
	boolean isBeanNameInUse(String beanName);

}
2. 具体实现DefaultListableBeanFactory

代码如下(示例):

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

// 省略

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

// 省略
}

到这里,基本上和前面的预期差不多,但是如果仔细看源码,其中的复杂程度远超想象。本文中,我们先关注BeanDefinition注册过程,忽略其他代码。


三、特色方法 removeBeanDefinition

既然都集合管理了,那么增删改查这套应该给整齐了。但具体什么时候会使用删除,后面的文章中我们再讨论。Spring中许多代码在写的时候,方法都是完整的,哪怕暂时用不到可以先留空。至少从逻辑上看,相关操作都是完整的。

BeanDefinitionOverriding

终点关注这个overriding,就意味着可以覆盖。既然可以覆盖总得有一些条件吧。咱们仔细看下源码。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		// 省略校验代码 
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
		     // 是否允许覆盖
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			// 角色比较
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			// 已存比较
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
		   // 容器已启动的特殊处理暂时忽略
	    }
	}

从代码中可以看到:

  1. 对于重名的BeanDefinition,如果不允许overriding直接异常;
  2. 如果允许overriding,先比较角色。这个角色在Spring中定义了3种,级别从低到高分别是ROLE_APPLICATION(用户定义Bean), ROLE_SUPPORT(Spring内部使用,可能跟用户有关), ROLE_INFRASTRUCTURE(Spring内部使用,和框架使用者完全无关)。越大优先级越高。高优先级可以覆盖低优先级的BeanDefinition。
  3. 如果允许overriding, 并且两个BeanDefinition不相等直接覆盖;
  4. 关于容器已启动时的特殊处理,后续文章再做讨论。
总结

以上就是今天要讲的内容,本文梳理了Spring中BeanDefinition的注册思路和实现过程。如果对你有所帮助,请让我知道,感谢你的阅读。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/822041.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号