您的位置:首页 > 编程语言 > Java开发

Spring源码分析-配置文件的解析(二)

2012-09-19 11:02 726 查看


上一节介绍了资源的定位,既然资源已经定位了,本章将进入具体的解析工作,具体的解析工作是从XmlBeanDefinitionReader类的loadBeanDefinitions(Resourceresource)方法开始。

一.loadBeanDefinitions(Resourceresource)源码如下XmlBeanDefinitionReader类

publicintloadBeanDefinitions(Resourceresource)
throwsBeanDefinitionStoreException
{
returnloadBeanDefinitions(newEncodedResource(resource));
}

EncodedResource是对Resource的封装,采用装饰模式,主要是增加了编码的信息.

	/**
*LoadbeandefinitionsfromthespecifiedXMLfile.
*@paramencodedResourcetheresourcedescriptorfortheXMLfile,
*allowingtospecifyanencodingtouseforparsingthefile
*@returnthenumberofbeandefinitionsfound
*@throwsBeanDefinitionStoreExceptionincaseofloadingorparsingerrors
*/
publicintloadBeanDefinitions(EncodedResourceencodedResource)throwsBeanDefinitionStoreException{
Assert.notNull(encodedResource,"EncodedResourcemustnotbenull");
if(logger.isInfoEnabled()){
logger.info("LoadingXMLbeandefinitionsfrom"+encodedResource.getResource());
}

SetcurrentResources=(Set)this.resourcesCurrentlyBeingLoaded.get();
if(currentResources==null){
currentResources=newHashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if(!currentResources.add(encodedResource)){
thrownewBeanDefinitionStoreException(
"Detectedrecursiveloadingof"+encodedResource+"-checkyourimportdefinitions!");
}
try{
InputStreaminputStream=encodedResource.getResource().getInputStream();
try{
InputSourceinputSource=newInputSource(inputStream);
if(encodedResource.getEncoding()!=null){
inputSource.setEncoding(encodedResource.getEncoding());
}
returndoLoadBeanDefinitions(inputSource,encodedResource.getResource());
}
finally{
inputStream.close();
}
}
catch(IOExceptionex){
thrownewBeanDefinitionStoreException(
"IOExceptionparsingXMLdocumentfrom"+encodedResource.getResource(),ex);
}
finally{
currentResources.remove(encodedResource);
if(currentResources.isEmpty()){
this.resourcesCurrentlyBeingLoaded.set(null);
}
}
}

这个方法里最核心的操作是doLoadBeanDefinitions(inputSource,encodedResource.getResource())

	/**
*ActuallyloadbeandefinitionsfromthespecifiedXMLfile.
*@paraminputSourcetheSAXInputSourcetoreadfrom
*@paramresourcetheresourcedescriptorfortheXMLfile
*@returnthenumberofbeandefinitionsfound
*@throwsBeanDefinitionStoreExceptionincaseofloadingorparsingerrors
*/
protectedintdoLoadBeanDefinitions(InputSourceinputSource,Resourceresource)
throwsBeanDefinitionStoreException{
try{
intvalidationMode=getValidationModeForResource(resource);
Documentdoc=this.documentLoader.loadDocument(
inputSource,getEntityResolver(),this.errorHandler,validationMode,isNamespaceAware());
returnregisterBeanDefinitions(doc,resource);
}
catch(BeanDefinitionStoreExceptionex){
throwex;
}
}


DocumentLoader类主要负责把一个XML文档解析成一个Document对象,注册beanDefinitions的工作交给registerBeanDefinitions方法了.

	/**
*RegisterthebeandefinitionscontainedinthegivenDOMdocument.
*Calledby<code>loadBeanDefinitions</code>.
*<p>Createsanewinstanceoftheparserclassandinvokes
*<code>registerBeanDefinitions</code>onit.
*@paramdoctheDOMdocument
*@paramresourcetheresourcedescriptor(forcontextinformation)
*@returnthenumberofbeandefinitionsfound
*@throwsBeanDefinitionStoreExceptionincaseofparsingerrors
*@see#loadBeanDefinitions
*@see#setDocumentReaderClass
*@seeBeanDefinitionDocumentReader#registerBeanDefinitions
*/
publicintregisterBeanDefinitions(Documentdoc,Resourceresource)throwsBeanDefinitionStoreException{
//SupportoldXmlBeanDefinitionParserSPIforbackwards-compatibility.
if(this.parserClass!=null){
XmlBeanDefinitionParserparser=
(XmlBeanDefinitionParser)BeanUtils.instantiateClass(this.parserClass);
returnparser.registerBeanDefinitions(this,doc,resource);
}
//ReaddocumentbasedonnewBeanDefinitionDocumentReaderSPI.
BeanDefinitionDocumentReaderdocumentReader=createBeanDefinitionDocumentReader();
intcountBefore=getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc,createReaderContext(resource));
returngetRegistry().getBeanDefinitionCount()-countBefore;
}


实际上XmlBeanDefinitionReader把解析注册的工作又转交给BeanDefinitionDocumentReader来完成了。

这里getRegistry()实际上返回的是上一节介绍的生成的DefaultListableBeanFactory,这个工厂实际上是在生成XmlBeanDefinitionReader对象时通过构造方法入参传入的。

这里的createReaderContext(Resourceresource)应该特别注意一下,这个上下文中包含了很多重要的信息,以提供给BeanDefinitionDocumentReader来使用。

	/**
*Createthe{@linkXmlReaderContext}topassovertothedocumentreader.
*/
protectedXmlReaderContextcreateReaderContext(Resourceresource){
if(this.namespaceHandlerResolver==null){
this.namespaceHandlerResolver=createDefaultNamespaceHandlerResolver();
}
returnnewXmlReaderContext(resource,this.problemReporter,this.eventListener,
this.sourceExtractor,this,this.namespaceHandlerResolver);
}


二:我们来看看DefaultBeanDefinitionDocumentReader是如何来registerBeanDefinitions的.

publicvoidregisterBeanDefinitions(Documentdoc,XmlReaderContextreaderContext)
{
this.readerContext=readerContext;
logger.debug("Loadingbeandefinitions");
Elementroot=doc.getDocumentElement();
BeanDefinitionParserDelegatedelegate=createHelper(readerContext,root);
preProcessXml(root);
parseBeanDefinitions(root,delegate);
postProcessXml(root);
}


可以看出DefaultBeanDefinitionDocumentReader又把解析注册的工作委托给BeanDefinitionParserDelegate来处理了,具体的工作见parseBeanDefinitions方法.

protectedvoidparseBeanDefinitions(Elementroot,BeanDefinitionParserDelegatedelegate)
{
if(delegate.isDefaultNamespace(root.getNamespaceURI()))
{
NodeListnl=root.getChildNodes();
for(inti=0;i<nl.getLength();i++)
{
org.w3c.dom.Nodenode=nl.item(i);
if(nodeinstanceofElement)
{
Elementele=(Element)node;
StringnamespaceUri=ele.getNamespaceURI();
if(delegate.isDefaultNamespace(namespaceUri))
parseDefaultElement(ele,delegate);
else
delegate.parseCustomElement(ele);
}
}

}else
{
delegate.parseCustomElement(root);
}
}

我们继续来看一下核心操作parseDefaultElement(ele,delegate)方法。

privatevoidparseDefaultElement(Elementele,BeanDefinitionParserDelegatedelegate)
{
if(DomUtils.nodeNameEquals(ele,"import"))
importBeanDefinitionResource(ele);
else
if(DomUtils.nodeNameEquals(ele,"alias"))
processAliasRegistration(ele);
else
if(DomUtils.nodeNameEquals(ele,"bean"))
processBeanDefinition(ele,delegate);
}

Xml配置文件中的bean的解析注册就在processBeanDefinition中了。

protectedvoidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate)
{
BeanDefinitionHolderbdHolder=delegate.parseBeanDefinitionElement(ele);
if(bdHolder!=null)
{
bdHolder=delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);
try
{
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
}
catch(BeanDefinitionStoreExceptionex)
{
getReaderContext().error("Failedtoregisterbeandefinitionwithname'"+bdHolder.getBeanName()+"'",ele,ex);
}
getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));
}
}


Spring把每一个Bean结点解析之后,生成底层的数据结构BeanDefinition,然后存储在BeanDefinitionHold中,很明显具体的真正的解析工作放在parseBeanDefinitionElement方法中,解析完成后则调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry())把beanDefinition注册到beanFactory中。下面,我们来看一下核心方法parseBeanDefinitionElement的源码.

三:我们来看看BeanDefinitionParserDelegate的parseBeanDefinitionElement(Elementele)是如何来解析的.

publicBeanDefinitionHolderparseBeanDefinitionElement(Elementele)
{
returnparseBeanDefinitionElement(ele,null);
}

publicBeanDefinitionHolderparseBeanDefinitionElement(Elementele,BeanDefinitioncontainingBean)
{
Stringid=ele.getAttribute("id");
StringnameAttr=ele.getAttribute("name");
Listaliases=newArrayList();
if(StringUtils.hasLength(nameAttr))
{
StringnameArr[]=StringUtils.tokenizeToStringArray(nameAttr,",;");
aliases.addAll(Arrays.asList(nameArr));
}
StringbeanName=id;
if(!StringUtils.hasText(beanName)&&!aliases.isEmpty())
{
beanName=(String)aliases.remove(0);
if(logger.isDebugEnabled())
logger.debug("NoXML'id'specified-using'"+beanName+"'asbeannameand"+aliases+"asaliases");
}
if(containingBean==null)
checkNameUniqueness(beanName,aliases,ele);
AbstractBeanDefinitionbeanDefinition=parseBeanDefinitionElement(ele,beanName,containingBean);
if(beanDefinition!=null)
{
if(!StringUtils.hasText(beanName))
try
{
if(containingBean!=null)
{
beanName=BeanDefinitionReaderUtils.generateBeanName(beanDefinition,readerContext.getRegistry(),true);
}else
{
beanName=readerContext.generateBeanName(beanDefinition);
StringbeanClassName=beanDefinition.getBeanClassName();
if(beanClassName!=null&&beanName.startsWith(beanClassName)&&beanName.length()>beanClassName.length()&&!readerContext.getRegistry().isBeanNameInUse(beanClassName))
aliases.add(beanClassName);
}
if(logger.isDebugEnabled())
logger.debug("NeitherXML'id'nor'name'specified-usinggeneratedbeanname["+beanName+"]");
}
catch(Exceptionex)
{
error(ex.getMessage(),ele);
returnnull;
}
StringaliasesArray[]=StringUtils.toStringArray(aliases);
returnnewBeanDefinitionHolder(beanDefinition,beanName,aliasesArray);
}else
{
returnnull;
}
}


在这里我们看到对id,name等属性的解析,最核心的操作为AbstractBeanDefinitionbeanDefinition=parseBeanDefinitionElement(ele,beanName,containingBean);

	/**
*Parsethebeandefinitionitself,withoutregardtonameoraliases.Mayreturn
*<code>null</code>ifproblemsoccuredduringtheparseofthebeandefinition.
*/
publicAbstractBeanDefinitionparseBeanDefinitionElement(
Elementele,StringbeanName,BeanDefinitioncontainingBean){

this.parseState.push(newBeanEntry(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;
}
catch(ClassNotFoundExceptionex){
error("Beanclass["+className+"]notfound",ele,ex);
}
catch(NoClassDefFoundErrorerr){
error("Classthatbeanclass["+className+"]dependsonnotfound",ele,err);
}
catch(Throwableex){
error("Unexpectedfailureduringbeandefinitionparsing",ele,ex);
}
finally{
this.parseState.pop();
}

returnnull;
}


在这段代码中,你可清楚的看到对bean组件相关属性和子标记的解析和处理(根据方法的命名).

四:在这里,可以重点关注一下ParseState

publicfinalclassParseState
{
publicstaticinterfaceEntry
{
}

publicParseState()
{
state=newStack();
}

privateParseState(ParseStateother)
{
state=(Stack)other.state.clone();
}

publicvoidpush(Entryentry)
{
state.push(entry);
}

publicvoidpop()
{
state.pop();
}

publicEntrypeek()
{
return(Entry)(state.empty()?null:state.peek());
}

publicParseStatesnapshot()
{
returnnewParseState(this);
}

publicStringtoString()
{
StringBuffersb=newStringBuffer();
for(intx=0;x<state.size();x++)
{
if(x>0)
{
sb.append('\n');
for(inty=0;y<x;y++)
sb.append('\t');

sb.append("->");
}
sb.append(state.get(x));
}

returnsb.toString();
}

privatestaticfinalcharTAB=9;
privatefinalStackstate;
}


这个类用了比较巧妙的方式来跟踪解析过程中的相关步骤,用户详见源码和API。

Simple
Stack
-basedstructurefortrackingthelogicalpositionduringaparsingprocess.

entries
areaddedtothestackateachpointduringtheparsephaseinareader-specificmanner.

Calling
toString()
willrenderatree-styleviewofthecurrentlogicalpositionintheparsephase.Thisrepresentationisintendedforuseinerrormessages.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: