spring中xml标签加载解析的一般过程
来源:互联网 发布:服务器域名怎么看 编辑:程序博客网 时间:2024/05/20 11:33
默认标签的解析过程:
DefaultBeanDefinitonDocumentReader class中processBeanDefinition
(1) 该方法先解析element元素获得BeanDefinitionHolder,
(2) 由BeanDefintionParserDelegate对于holder进行装饰加工
(3) 由BeanDefinitionReaderUtils.registerBeanDefinition对于holder进行注册
(4) 之后发送注册事件getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))
其中主要的方法如下:
protected voidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate) {
BeanDefinitionHolderbdHolder=delegate.parseBeanDefinitionElement(ele);//(1)
if (bdHolder !=null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);//(2)
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());//(3)
}
catch(BeanDefinitionStoreExceptionex) {
getReaderContext().error("Failed to register bean definition with name'" +
bdHolder.getBeanName() +"'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));//(4)
}
}
下面细节介绍首先是
(1) 对于element元素的解析
BeanDefinitionHolder bdHolder=delegate.parseBeanDefinitionElement(ele);
delegate:BeanDefinitionParserDelegate该类主要是完成对于element的解析工作,位于org.springframework.beans.factory.xml包下
public BeanDefinitionHolderparseBeanDefinitionElement(Elementele){
returnparseBeanDefinitionElement(ele,null);
}
该方法提供解析element,如果解析出错会返回一个null。
它调用如下的方法进行解析,string id ID_ATTRIBUTE 指的是常亮字符“id”<bean id>这里面的,name也是类似。
public BeanDefinitionHolderparseBeanDefinitionElement(Elementele,BeanDefinitioncontainingBean) {
//对应id name 等标签
Stringid = ele.getAttribute(ID_ATTRIBUTE);
StringnameAttr= ele.getAttribute(NAME_ATTRIBUTE);
List<String>aliases= newArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[]nameArr= StringUtils.tokenizeToStringArray(nameAttr,MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
StringbeanName= 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");
}
}
if (containingBean ==null) {
checkNameUniqueness(beanName,aliases, ele);
}
//解析的BeanDefinition放到GenericBeanDefintion中
AbstractBeanDefinitionbeanDefinition= parseBeanDefinitionElement(ele,beanName,containingBean);
if (beanDefinition !=null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean !=null) {
beanName =BeanDefinitionReaderUtils.generateBeanName(
beanDefinition,this.readerContext.getRegistry(),true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
StringbeanClassName=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 (Exceptionex) {
error(ex.getMessage(),ele);
returnnull;
}
}
String[]aliasesArray= StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition,beanName, aliasesArray);
}
return null;
}
(a)其中调用spring框架中的StringUtils类,并使用Java.util.StringTokenizer类进行字符串分割获得有用数据,然后添加到alisases:list中;
(b)先删除掉该beanName(id),然后再检测在当前的beandefinition nest中没有使用该bean,然后解析。
(c) AbstractBeanDefinition beanDefinition =parseBeanDefinitionElement(ele,beanName,containingBean);
获得一个beandefinition,只不过这里将该对象引用给了它的抽象的父类,
该方法首先是
This.parseState.push(newBeanEntry(beanName));
new BeanEntry(String beanName)是beanEntry的一个构造方法,该类主要表示一个BeanDefinition 。
BeanDefinition是一个接口,其中定义了一些在xml中,bean<bean>定义的标签的对应的属性,其中有我们熟悉的lazyInit,
public interfaceBeanDefinition extends AttributeAccessor, BeanMetadataElement {
StringSCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
StringSCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT= 1;
int ROLE_INFRASTRUCTURE= 2;
StringgetParentName();
void setParentName(StringparentName);
StringgetBeanClassName();
void setBeanClassName(StringbeanClassName);
StringgetFactoryBeanName();
voidsetFactoryBeanName(StringfactoryBeanName);
StringgetFactoryMethodName();
voidsetFactoryMethodName(StringfactoryMethodName);
StringgetScope();
void setScope(Stringscope);
boolean isLazyInit();
void setLazyInit(booleanlazyInit);
String[]getDependsOn();
void setDependsOn(String[]dependsOn);
boolean isAutowireCandidate();
void setAutowireCandidate(booleanautowireCandidate);
boolean isPrimary();
void setPrimary(booleanprimary);
ConstructorArgumentValuesgetConstructorArgumentValues();
MutablePropertyValuesgetPropertyValues();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
int getRole();
StringgetDescription();
StringgetResourceDescription();
BeanDefinitiongetOriginatingBeanDefinition();
}
AbstractBeanDefintion则是对于BeanDefinition接口的实现类,实现了其中操作属性的方法,可以将<bean> 中属性加载到该类中,是xml文件的一种对象转换。
之后className = ele.getAttribute(CLASS_ATTRIBUTE).trim();获得其classname.
并获得其父类string parent,然后用
AbstractBeanDefinition db =creatBeanDefinition(className,parent);
创建出beandefinition,该create方法则是利用了BeanDefinitionReaderUitls工具类的createBeanDefinition(parentName,className,this.readerContext.getBeanClassLoader())实现的,具体如下:
public staticAbstractBeanDefinitioncreateBeanDefinition(
StringparentName,StringclassName,ClassLoader classLoader)throwsClassNotFoundException {
GenericBeanDefinition bd =new GenericBeanDefinition();
bd.setParentName(parentName);
if (className !=null) {
if (classLoader !=null) {
bd.setBeanClass(ClassUtils.forName(className,classLoader));
}
else {
bd.setBeanClassName(className);
}
}
returnbd;
}
之后是:
public AbstractBeanDefinitionparseBeanDefinitionElement(
Elementele,String beanName,BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
StringclassName= null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)){
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
Stringparent= null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)){
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinitionbd =createBeanDefinition(className,parent);
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));
returnbd;
}……
接着是如上的解析beandefinition的属性,设置description,解析metaelements,并且解析subElements,解析替代方法子元素parseReplacedMethodSubElements,解析构造器中参数elements,解析属性elements,设置资源等等。
然后返回到parseBeanDefinitionElement():,这些解析的具体的内容可以参考郝佳编著的《spring源码深度解析》中第三章的内容。BeanDefintionParseDelegate中继续执行,
最后将这个beandefinition和beanname都放到beandefinitionholder中,返回。即返回到DefaultBeanDefinitionDocumentReader类下的processBeanDefintion()方法。
(2) 对于holder进行修饰(装饰)
bdHolder= delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);
里面利用了NamespaceHandler,命名空间的修饰,是不是默认的标签还是用户自定义的,可以通过其内容之进行判断。默认的标志为"http://www.springframework.org/schema/beans"
,其他用户自定义的标签由相应的NamespaceHandler进行处理。
(3) 注册最终的装饰后的bdholder类,
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
使用相应的beandefinitionfactory进行相应的holder注册
public staticvoidregisterBeanDefinition(
BeanDefinitionHolderdefinitionHolder,BeanDefinitionRegistryregistry)
throwsBeanDefinitionStoreException {
// Register bean definition under primary name.
StringbeanName= definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[]aliases= definitionHolder.getAliases();
if (aliases !=null) {
for (Stringaliase : aliases) {
registry.registerAlias(beanName,aliase);
}
}
}
DefaultListBeanFactory中有一个实现了registryBeanDefinition()的方法,可以参考。一种是通过beanName注册,另外一种是通过alias别名进行注册。
beanName注册是将BeanName和BeanDefinition一起以Map <key value>形式加入到BeanDefintionMap中,其步骤为
(a1)进行一些验证(方法属性是否有);
(a2)然后判断是否可以覆盖,不可则抛出异常;
(a3)然后添加beanName到map中;
(a4)最后则是重置所有对应的缓存。
存在于DefaultListableBeanFactory中:
public void registerBeanDefinition(StringbeanName, BeanDefinition beanDefinition)
throwsBeanDefinitionStoreException {
Assert.hasText(beanName,"Bean name must not be empty");
Assert.notNull(beanDefinition,"BeanDefinition must not be null");
if (beanDefinitioninstanceofAbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
}
catch(BeanDefinitionValidationExceptionex) {
throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,
"Validation of bean definition failed",ex);
}
}
BeanDefinitionoldBeanDefinition;
synchronized (this.beanDefinitionMap){
oldBeanDefinition= this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition!=null){
if (!this.allowBeanDefinitionOverriding) {
throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,
"Cannot register bean definition [" +beanDefinition+ "] for bean '" +beanName+
"': There is already ["+oldBeanDefinition+ "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" +beanName+
"': replacing ["+oldBeanDefinition+ "] with [" + beanDefinition+ "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames=null;
}
this.beanDefinitionMap.put(beanName,beanDefinition);
}
if (oldBeanDefinition!=null|| containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
通过alias别名注册的情况则是SimpleAliasRegistry中的实现了该方法:
public voidregisterAlias(String name, Stringalias){
Assert.hasText(name,"'name' must not be empty");
Assert.hasText(alias,"'alias' must not be empty");
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
if(!allowAliasOverriding()) {
StringregisteredName=this.aliasMap.get(alias);
if (registeredName !=null && !registeredName.equals(name)) {
throw new IllegalStateException("Cannot register alias '" +alias+ "' for name '" +
name + "': It is already registered for name '" + registeredName+"'.");
}
}
checkForAliasCircle(name,alias);
this.aliasMap.put(alias,name);
}
}
(b1)如果有alias别名和beanName相同的先从aliasmap中移除,
(b2)如果不允许相同别名的覆盖,则会抛出异常
(b3)检查是否有循环的情况A->B ,A->C->B的情况
(b4)将alias和name添加到别名map中
(4)注册事件传递(注册监听)// Send registration event.
getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));
readercontext中注册该监听事件
public voidfireComponentRegistered(ComponentDefinitioncomponentDefinition){
this.eventListener.componentRegistered(componentDefinition);
}
其中的参数可以是如下构造,显示本身,然后是内部的beandefinition和参考设置。
public BeanComponentDefinition(BeanDefinitionHolderholder){
super(holder);
findInnerBeanDefinitionsAndBeanReferences(holder.getBeanDefinition());
}
- spring中xml标签加载解析的一般过程
- spring解析xml标签过程
- Spring bean 标签加载、解析过程分析
- Spring bean 标签加载、解析过程分析
- spring源码-2-xml标签的解析
- Spring XML解析过程
- spring xml解析过程
- Spring自定义标签和spring.handlers的加载过程
- 在Spring的XML文件中通过命名空间配置的标签是怎么解析的?
- spring中IOC容器中的xml加载过程
- Spring是如何加载XML文件中的标签的
- SSM中Spring双亲容器的构造过程和XML加载顺序
- spring 中加载xml配置文件的方式.
- spring 中加载xml配置文件的方式.
- spring 中加载xml配置文件的方式
- Spring中加载XML配置文件的方式
- spring 中加载xml配置文件的方法
- spring中加载xml配置文件的方式
- APP在Android5.0上运行时闪退
- 【ValueError: math domain error】
- Mongodb存储过程使用
- 关于在平台中设置系统全局变量的使用和场景
- java获取某个字符在一个字符串中出现的下标(从0开始)
- spring中xml标签加载解析的一般过程
- Java 序列化--- Kryo使用简单例子
- ueditor 配置无效?
- Android开发学习笔记:Intent的简介以及属性的详解
- 【iOS】GitHub删除respository(仓库)、fork项目
- Xcode更新后.xcodeporj变为白色了
- 根据浏览器 user-agent 按需加载CSS 文件
- 冒泡排序和选择排序
- java 操作hbase的数据