文档章节

基于XmlBeanFactory加载bean分析:parseDefaultElement(二)

qwweeezhengwei
 qwweeezhengwei
发布于 2017/08/07 16:31
字数 1818
阅读 11
收藏 0

本节主要针对bean标签的解析源码分析

DefaultBeanDefinitionDocumentReader.java 完成了对element的解析

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	if(delegate.nodeNameEquals(ele, "import")) {//导入
		this.importBeanDefinitionResource(ele);
	} else if(delegate.nodeNameEquals(ele, "alias")) {//别名
		this.processAliasRegistration(ele);
	} else if(delegate.nodeNameEquals(ele, "bean")) {//bean
		this.processBeanDefinition(ele, delegate);
	} else if(delegate.nodeNameEquals(ele, "beans")) {//bean集合
		this.doRegisterBeanDefinitions(ele);
	}

}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	//通过BeanDefinition解析器去解析ele,然后返回BeanDefinitionHolder(也就是返回具体的BeanDefinition,beanName,ailas)
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//【分支01】
	if(bdHolder != null) {
		//bdHolder实例不为空,需要对标签下的自定义标签,再次解析//【分支02】
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

		try {
			//当拿到BeanDefinitionHolder后,需要将解析的bean注册到Spring容器中//【分支03】
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
		} catch (BeanDefinitionStoreException var5) {
			this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5);
		}

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

}

【分支01】主要分析了如果把element解析为一个BeanDefinitionHolder对象

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
}
//具体的bean解析(当前分析时containingBean为空)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
	String id = ele.getAttribute("id");//在element节点中获取id属性
	String nameAttr = ele.getAttribute("name");//在element节点获取name属性
	//---处理alias开始
	ArrayList aliases = new ArrayList();//将所有的name都当成别名先记录起来
	if(StringUtils.hasLength(nameAttr)) {
		String[] beanName = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
		aliases.addAll(Arrays.asList(beanName));
	}
	//---处理alias结束
	String beanName1 = id;
	//这里如果发现未设置id属性时,直接从name属性中获取,然后移除一个name属性
	if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
		beanName1 = (String)aliases.remove(0);
	}
	//验证name以及别名信息是否唯一【分支0101】
	if(containingBean == null) {
		this.checkNameUniqueness(beanName1, aliases, ele);
	}
	//创建一个beanDefinition对象【分支0102】
	AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean);
	if(beanDefinition != null) {
		if(!StringUtils.hasText(beanName1)) {
			try {
				if(containingBean != null) {
					beanName1 = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
				} else {
					beanName1 = this.readerContext.generateBeanName(beanDefinition);
					String aliasesArray = beanDefinition.getBeanClassName();
					if(aliasesArray != null && beanName1.startsWith(aliasesArray) && beanName1.length() > aliasesArray.length() && !this.readerContext.getRegistry().isBeanNameInUse(aliasesArray)) {
						aliases.add(aliasesArray);
					}
				}

				if(this.logger.isDebugEnabled()) {
					this.logger.debug("Neither XML \'id\' nor \'name\' specified - using generated bean name [" + beanName1 + "]");
				}
			} catch (Exception var9) {
				this.error(var9.getMessage(), ele);
				return null;
			}
		}

		String[] aliasesArray1 = StringUtils.toStringArray(aliases);
		return new BeanDefinitionHolder(beanDefinition, beanName1, aliasesArray1);
	} else {
		return null;
	}
}

【分支0101】验证name以及别名信息是否唯一

BeanDefinitionParserDelegate.java中

--【分支0101】验证name以及别名信息是否唯一
private final Set<String> usedNames = new HashSet();
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
	String foundName = null;
	//查询usedNames是否包含当前beanName
	if(StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
		foundName = beanName;
	}

	//判断当前别名与已注册的usedNames信息是否相同
	if(foundName == null) {
		foundName = (String)CollectionUtils.findFirstMatch(this.usedNames, aliases);
	}

	if(foundName != null) {
		this.error("Bean name \'" + foundName + "\' is already used in this <beans> element", beanElement);
	}
	//usedNames存放了beanName和alias信息
	this.usedNames.add(beanName);
	this.usedNames.addAll(aliases);
}

这里主要使用了

Set集合存储usedNames,其中usedNames包含beanName以及aliases信息。

【分支0102】创建一个beanDefinition对象(其原型类为AbstractBeanDefinition)

BeanDefinitionParserDelegate.java中

AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean);
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
	this.parseState.push(new BeanEntry(beanName));
	String className = null;
	//获取当前节点的class属性
	if(ele.hasAttribute("class")) {
		className = ele.getAttribute("class").trim();
	}

	try {
		String ex = null;
		//判断并获取当前节点的parent属性
		if(ele.hasAttribute("parent")) {
			ex = ele.getAttribute("parent");
		}
		//下面描述了AbstractBeanDefinition如何创建并且讲解了AbstractBeanDefinition相关类图结构以了解具体里面干了些什么事
		AbstractBeanDefinition bd = this.createBeanDefinition(className, ex);
		//当拿到bean属性BeanDefinition之后,通过当前element节点信息,基础设置AbstractBeanDefinition的属性
		this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		//设置description描述信息
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
		//处理meta标签(实际开发中好像还没使用到过)
		this.parseMetaElements(ele, bd);
		//处理lookup-method标签
		this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		//处理replaced-method标签
		this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		//处理构造函数constructor-arg标签
		this.parseConstructorArgElements(ele, bd);
		//处理property标签
		this.parsePropertyElements(ele, bd);
		//处理qualifier标签
		this.parseQualifierElements(ele, bd);
		//设置resource属性
		bd.setResource(this.readerContext.getResource());
		//设置source属性
		bd.setSource(this.extractSource(ele));
		AbstractBeanDefinition var7 = bd;
		return var7;
	} catch (ClassNotFoundException var13) {
		this.error("Bean class [" + className + "] not found", ele, var13);
	} catch (NoClassDefFoundError var14) {
		this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
	} catch (Throwable var15) {
		this.error("Unexpected failure during bean definition parsing", ele, var15);
	} finally {
		this.parseState.pop();
	}

	return null;
}

我们看到上面处理了很多标签,这些标签都是我们日常在xml配置的属性节点。也就是这里主要完成xml配置中对属性节点的解析。

this.createBeanDefinition(className, ex)创建一个AbstractBeanDefinition

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException {
	return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}

BeanDefinitionReaderUtils.createBeanDefinition方法

public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
	//GenericBeanDefinition为AbstractBeanDefinition的实现类;这里主要完成GenericBeanDefinition的初始化工作,调用了AbstractBeanDefinition无参的构造函数完成基本信息的初始化等
	GenericBeanDefinition bd = new GenericBeanDefinition();
	bd.setParentName(parentName);
	if(className != null) {
		if(classLoader != null) {
			bd.setBeanClass(ClassUtils.forName(className, classLoader));
		} else {
			bd.setBeanClassName(className);
		}
	}

	return bd;
}

然后我们回到【分支0102】分支中的

//当拿到bean属性BeanDefinition之后,通过当前element节点信息,基础设置AbstractBeanDefinition的属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

//设置AbstractBeanDefinition属性的值
//这里面主要完成了对element节点信息的获取和解析并将解析的参数设置到AbstractBeanDefinition中,完成AbstractBeanDefinition的进一步初始化
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
	//这里明确说明,在1.x以后singleton标签已经被scope作用域标签代替【scope可选值:singleton,prototype,request,session】
	if(ele.hasAttribute("singleton")) {
		this.error("Old 1.x \'singleton\' attribute in use - upgrade to \'scope\' declaration", ele);
	} else if(ele.hasAttribute("scope")) {//如果包含scope则设置AbstractBeanDefinition中的scope属性
		bd.setScope(ele.getAttribute("scope"));
	} else if(containingBean != null) {//这里明确如果包含containingBean那么作用域肯定在containingBean中。但是根据规则以socpe为主
		bd.setScope(containingBean.getScope());
	}
	
	//设置AbstractBeanDefinition的abstract 是否为抽象类的标识
	if(ele.hasAttribute("abstract")) {
		bd.setAbstract("true".equals(ele.getAttribute("abstract")));
	}
	//设置延迟初始
	String lazyInit = ele.getAttribute("lazy-init");
	if("default".equals(lazyInit)) {
		lazyInit = this.defaults.getLazyInit();
	}

	bd.setLazyInit("true".equals(lazyInit));
	String autowire = ele.getAttribute("autowire");
	//这里在当前getAutowireMode方法中去查找自动注入方式;
	//我们看到当前类存在这样一个属性private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();在populateDefaults方法完成document文档根节点类的加载。例如在根节点上面设置default-autowire="byType"等设置
	bd.setAutowireMode(this.getAutowireMode(autowire));
	String dependencyCheck = ele.getAttribute("dependency-check");
	bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
	String autowireCandidate;
	if(ele.hasAttribute("depends-on")) {
		autowireCandidate = ele.getAttribute("depends-on");
		bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
	}

	autowireCandidate = ele.getAttribute("autowire-candidate");
	String destroyMethodName;
	if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
		bd.setAutowireCandidate("true".equals(autowireCandidate));
	} else {
		destroyMethodName = this.defaults.getAutowireCandidates();
		if(destroyMethodName != null) {
			String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
			bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
		}
	}

	if(ele.hasAttribute("primary")) {
		bd.setPrimary("true".equals(ele.getAttribute("primary")));
	}

	if(ele.hasAttribute("init-method")) {
		destroyMethodName = ele.getAttribute("init-method");
		if(!"".equals(destroyMethodName)) {
			bd.setInitMethodName(destroyMethodName);
		}
	} else if(this.defaults.getInitMethod() != null) {
		bd.setInitMethodName(this.defaults.getInitMethod());
		bd.setEnforceInitMethod(false);
	}

	if(ele.hasAttribute("destroy-method")) {
		destroyMethodName = ele.getAttribute("destroy-method");
		bd.setDestroyMethodName(destroyMethodName);
	} else if(this.defaults.getDestroyMethod() != null) {
		bd.setDestroyMethodName(this.defaults.getDestroyMethod());
		bd.setEnforceDestroyMethod(false);
	}

	if(ele.hasAttribute("factory-method")) {
		bd.setFactoryMethodName(ele.getAttribute("factory-method"));
	}

	if(ele.hasAttribute("factory-bean")) {
		bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
	}

	return bd;
}

对其他标签的分析可以单独列出来分析,这里就不具体分析了。

切入【分支03】当拿到BeanDefinitionHolder后,需要将解析的bean注册到Spring容器中

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

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
	//获取当前注册的beanName
	String beanName = definitionHolder.getBeanName();
	//registry为xmlBeanFactory,他就是一个bean工厂类主要就是完成bean的注册
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
	String[] aliases = definitionHolder.getAliases();
	if(aliases != null) {
		String[] var4 = aliases;
		int var5 = aliases.length;

		for(int var6 = 0; var6 < var5; ++var6) {
			String alias = var4[var6];
			registry.registerAlias(beanName, alias);
		}
	}

}

//在实现类DefaultListableBeanFactory完成了registerBeanDefinition注册bean

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");
	if(beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition)beanDefinition).validate();
		} catch (BeanDefinitionValidationException var9) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
		}
	}

	BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
	if(oldBeanDefinition != null) {
		if(!this.isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean \'" + beanName + "\': There is already [" + oldBeanDefinition + "] bound.");
		}

		if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
			if(this.logger.isWarnEnabled()) {
				this.logger.warn("Overriding user-defined bean definition for bean \'" + beanName + "\' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		} else if(!beanDefinition.equals(oldBeanDefinition)) {
			if(this.logger.isInfoEnabled()) {
				this.logger.info("Overriding bean definition for bean \'" + beanName + "\' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
			}
		} else if(this.logger.isDebugEnabled()) {
			this.logger.debug("Overriding bean definition for bean \'" + beanName + "\' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
		}

		this.beanDefinitionMap.put(beanName, beanDefinition);
	} else {
		if(this.hasBeanCreationStarted()) {
			Map var4 = this.beanDefinitionMap;
			synchronized(this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				ArrayList updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				if(this.manualSingletonNames.contains(beanName)) {
					LinkedHashSet updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		} else {
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
		}

		this.frozenBeanDefinitionNames = null;
	}

	if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
		this.resetBeanDefinition(beanName);
	}

}

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

qwweeezhengwei
粉丝 0
博文 13
码字总数 31124
作品 0
成都
私信 提问
【Spring】BeanFactory解析bean详解

在该文中来讲讲Spring框架中BeanFactory解析bean的过程,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,先来看一个在Spring中一个基本的bean定义与使用。 Spring配置文件r...

weknow
2017/04/05
0
0
spring源码-bean之初始化-1

  一、spring的IOC控制反转:控制反转——Spring通过一种称作控制反转(IOC)的技术促进了松耦合。当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建...

小不点丶
2018/08/09
0
0
【Spring】BeanFactory解析bean详解

本文是Spring源码分析中的一篇,来讲讲Spring框架中BeanFactory解析bean的过程,先来看一个在Spring中一个基本的bean定义与使用。(也可以点击公号查看) Spring配置文件root.xml定义如下: ...

weknow
2018/09/09
82
0
XmlBeanFactory的初始化

XmlBeanFactory继承DefaultListableBeanFactory,关系图如下 内部通过XmlBeanDefinitionReader来从xml中读取bean的定义,即委托给XmlBeanDefinitionReader,XmlBeanDefinitionReader是读取x...

五年级小学生
07/01
4
0
【Spring】- IOC容器初始化过程

IOC容器案例:XmlBeanFactory XmlBeanFactory容器初始化过程: 步骤1:XmlBeanFactory 使用 ClassPathResource 映射Spring XML配置文件~ new ClassPathResource("com/zhiwei/ioc/application......

ZeroneLove
03/02
7
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
48分钟前
4
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
50分钟前
7
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
52分钟前
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
58分钟前
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部