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

Spring框架之BeanDefinition源码分析

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

Spring框架之BeanDefinition源码分析

文章目录

前言一、BeanDefinition二、BeanDefinitionBuilder三、BeanDefinitionHolder四、BeanDefinitionParserDelegate五、BeanDefinitiondocumentReader六、BeanDefinitionRegistry总结


前言

在分析Spring IOC中bean的创建执行流程的时候,遇到了这么一个对象BeanDefinition,其实呢这个也挺重要的,bean工厂创建对象就是根据这个来的,这里面记录了装配到容器中所有的bean对象信息,由于篇幅过长就单独提出来写了一篇文章来介绍。

一、BeanDefinition

继续顺着前面的思路走,前面说到在刷新获取BeanFactory的时候做了这么一件事:加载BeanDefinition

loadBeanDefinitions(beanFactory);

我们找到BeanDefinition,由于它是个接口我们看它默认的实现子类AbstractBeanDefinition。咱看一下这个类里面的一些属性,其实就可以看出来,这个装载了很多我们初始化bean配置的信息,例如单例、懒加载等。

	...
	private volatile Object beanClass;
	private String scope = SCOPE_DEFAULT; //单例,默认为单例
	private boolean abstractFlag = false;
	private Boolean lazyInit; //是否懒加载
	private int autowireMode = AUTOWIRE_NO; //自动装配
	private int dependencyCheck = DEPENDENCY_CHECK_NONE; //默认不检查依赖
	private String[] dependsOn; //依赖的bean列表
	private boolean autowireCandidate = true;
	private boolean primary = false;
	private final Map qualifiers = new linkedHashMap<>();
	private Supplier instanceSupplier;
	private boolean nonPublicAccessAllowed = true;
	private boolean lenientConstructorResolution = true;
	private String factoryBeanName;  //创建bean的bean工厂名称
	private String factoryMethodName; //创建bean的bean工厂方法
	private ConstructorArgumentValues constructorArgumentValues; //有参构造的参数
	private MutablePropertyValues propertyValues;	//bean的属性及对应名称
	private MethodOverrides methodOverrides = new MethodOverrides(); //被覆盖的方法
	private String initMethodName;  //初始化和销毁方法
	private String destroyMethodName;
	private boolean enforceInitMethod = true;   //是否需要执行初始化和销毁方法
	private boolean enforceDestroyMethod = true;
	private boolean synthetic = false;
	private int role = BeanDefinition.ROLE_APPLICATION;
	private String description;	//一些描述信息等
	private Resource resource; //定义bean的资源
	...

看了一下其实这个类没有什么复杂的内容,只是对我们配置的beans.xml进行了解析,然后把相关配置写到了属性中,可以在DefaultListableBeanFactory注册BeanDefinition的方法(registerBeanDefinition)中打个断点看一下。

这个类简单的理解可以当做Bean对象的Entity,我们找一些用到这个类的类,方法其实很简单,用这个类作为开头全局搜一下相关的类分析一下可以找到许多,找几个看一下。

二、BeanDefinitionBuilder

看名称就知道这是BeanDefinition的构建器,具体干啥的呢看一下内部的方法。可以看到其内部的许多方法都与上面的BeanDefinition中的属性相配合的,可以用其手动的构建一个BeanDefinition对象。
来手动试一下:

public static void main(String[] args) {
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class) ;
		beanDefinitionBuilder
				.addPropertyValue("name","张三")
				.addPropertyValue("age",18)
				.setScope("singleton");
		BeanDefinition beanDefinition= beanDefinitionBuilder.getBeanDefinition() ;
		System.out.println(beanDefinition);//这一行是用来打断点的
	}

可以看到可以使用其手动的构建一个BeanDefinition对象

三、BeanDefinitionHolder

BeanDefinition的持有者,其内部有两个属性是beanName也就是XML中配置的BeanId,还有一个是BeanDefinition,方法上没有什么特殊的方法。

四、BeanDefinitionParserDelegate

其实本来想看BeanDefinitiondocumentReader类的,但是其内部涉及到了这个类就先看一下它了,名称直译意思是BeanDefinition转换的委托类,点进去后看到了啥,一堆和Bean的XML配置相关的信息,也就是说它是Bean对象由XML转换为BeanDefinition的委托类。
再里面巴拉巴拉相关的方法,看了其中的方法名就知道核心方法是把XML转换为BeanDefinition对象的方法

//大家应该都知道Element是XML解析完的对象,BeanName是XML中配置的beanID
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		...
		try {
			//新创建一个BeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//下面是解析相关的内容放到BeanDefinition对应的属性中,具体干啥就不细看了
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DEscriptION_ELEMENT));
			parsemetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			parseConstructorArgElements(ele, bd);
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);
			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));
			return bd;
		}
		...
	}

还有一个重写的方法最终解析为BeanDefinitionHolder,BeanDefinition的持有者对象。

五、BeanDefinitiondocumentReader

同样看名称就明白这是从document文档例如XML中读取配置BeanDefinition的,直接看一下其核心方法,由于它是个接口,我们看它默认的实现子类DefaultBeanDefinitiondocumentReader中的方法,看其参数是Element类型的,这个大家应该熟悉是XML的解析类型,也就是说到了这里XML已经被解析成了Element对象了,还有一个参数是BeanDefinitionParserDelegate类型的,来解析Element变成BeanDefinition的

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);
					}
				}
			}
		}
		...
	}
	//根据断点最终走到了这个方法,最后解析为了持有者对象
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		...
		// 发送注册事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

BeanComponentDefinition
本来搜不到它的,但是打断点分析的过程用到了它,看一下相关的源代码信息,一个BeanDefinition的数组和一个BeanReference的数组,怎么说呢,这个类继承了BeanDefinitionHolder,但是其内部不是单个的了,而是放了多个相关的BeanDefinition信息。

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

这一行其实是监听器,有没有发现一个问题,当走到这里方法的返回参数为void空的,但是Bean对象的相关配置从XML中解析出来了,发现这里是空的,后面没有了,往回找,肯定是哪个方法漏掉了细节,最终找到了

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

这里最终指向了BeanDefinitionRegistry类,BeanDefinitionRegistry管理类,来看一下。

六、BeanDefinitionRegistry

其实只简单的看了一下BeanDefinition这个类的一些属性可以判断这就是记录bean的一些配置信息,工厂用来实例化bean的时候就根据这些配置信息来获取。咱看一下使用BeanDefinition类的注册类BeanDefinitionRegistry,这是个接口,看其提供的方法都是一些BeanDefinition的管理方法。

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);
}

具体的其实可以看其子类DefaultListableBeanFactory,里面有这么一个属性,这就是传说中的bean容器,以配置文件中的id为key存放了N多Bean的模板,其实看上面的注册移除管理就比较简单了,可以理解为Map的操作。

private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

到此,XML解析(当然这只是后面,前面XML解析为document到Element就不写了,有空再说)为BeanDefinition后面放到容器里的顺序捋清了。

总结


按照上面的分析最终梳理出来这么个逻辑:

    前面操作把Beans.xml解析成了document Element对象,这些省略了。调用BeanDefinitiondocumentReader中的parseBeanDefinitions()方法。parseBeanDefinitions又调用了BeanDefinitionParserDelegate中的parseBeanDefinitionElement()方法,将Element转换成了BeanDefinitionHolder。parseBeanDefinitionElement()中有一步操作,调用Utils将BeanDefinitionHolder中的BeanDefinition注册到DefaultBeanDefinitiondocumentReader内部的容器中。DefaultBeanDefinitiondocumentReader最终通过registerBeanDefinition将BeanDefinition放到了一个Map对象中,这就是对象管理的容器。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768547.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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