Spring 源码阅读(IOC容器)-容器启动2 2.2.3 资源定位、解释
2.2.3.1 资源定位加载与容器的关系
loadBeanDefinitions方法主要是加载BeanDefinition,而BeanDefinition的定义是来自于一组资源的,要加载BeanDefinition,Spring首先要加载、解释这些资源,资源的定位、加载由ResourceLoader与ResourcePatternResolver负责。
在loadBeanDefinitions方法分析之前,我们先来了解下容器与ResourceLoader之间的联系。ResourceLoader是资源加载器接口;ResourcePatternResolver是资源模式解释器接口,它把一个定位模式(例如,ant样式模式)转变为Resource对象; ResourcePatternResolver扩展自ResourceLoader,因此也可以说一个ResourcePatternResolver的实现在同时具备资源模式解释的同时,也具备资源的加载功能呢(关于继承结构参见图1)。
那么容器与ResourceLoader、ResourcePatternResolver在结构上有什么联呢?
首先,看一下
接口ApplicationContext与ResourcePatternResolver的关系:
从代码中可以看到,任何的上下文容器都应该支持资源模式的解释的功能,即能够解释ant-style的资源定义。我们看到了应用上下文接口声明支持资源模式的解释功能,那么具体的应用上下文容器是如何实现资源的定位以及资源模式的解释的呢?
接下来,我们看一下抽象类AbstractApplicationContext与ResourceLoader、ResourcePatternResolver的关系:
由代码可以看出,资源模式解释器在容器创建时就已经创建,资源模式解释器由PathMatchingResourcePatternResolver担当。AbstractApplicationContext继承于DefaultResourceLoader(ResourceLoader的默认实现),因此AbstractApplicationContext也具备了资源加载的功能。同时ApplicationContext扩展了ResourcePatternResolver接口,所以ApplicationContext的实现类对外表现的Loader应该为ResourcePatternResolver。通俗来讲,就是说容器具备资源模式解释的功能,并能对一资源位置进行加载,参看图-1理解一下。
知道了容器与ResourceLoader之间的联系,我们继续loadBeanDefinitions方法的分析。
2.2.3.2 loadBeanDefinitions方法分析
我们在上一节refreshBeanFactory方法中知道,内部工厂初始化的最后一步是加载BeanDefinition。loadBeanDefinitions方法是由抽象AbstractXmlApplicationContext
实现的。它在这里主要做了以下功能:把加载Definition(从字面上就能看出,其是对xml中的bean的定义)的工作委托给XmlBeanDefinitionReader,XmlBeanDefinitionReader来进行资源的定位,资源的加载。
2.2.3.3资源定位(resource location)分析
资源定位的定义主要包含两类:单一的资源路径和带有占位符的复合资源路径,其中后一种Spring支持ant-style样式的定义,例如classpath*:/WEF-INF/*-con.xml。无论是哪种类型的资源定位,最后都需要被解释成Resource(资源)。其中第一种由DefaultResourceLoader负责,其实现是通过资源定位尝试构造URL,然后把URL封装成URLResource;后一种由PathMatchingResourcePatternResolver负责,其主要处理ant-style样式的资源定位,其处理的资源主要包括两类:文件系统文件、jar文件(jar、zip、wsjar等),其返回的资源可能包括URLResource、FileSystemResource。
类PathMatchingResourcePatternResolver资源定位:
DefaultResourceLoader资源定位:
2.2.4 资源的解释以及BeanDefinition的注册
2.2.4.1 doLoadBeanDefinitions方法分析
我们在2.2.3.2节中提到,doLoadBeanDefinitions方法真正进行了资源的加载、解释工作。下面我们看看doLoadBeanDefinitions的实现。
2.2.4.1.1 BeanDefinitionDocumentReader对加载的Document的处理以及Bean注册
spring把解释xml,并发解释的数据转化为BeanDefinition的任务委派给BeanDefinitionDocumentReader,其解释的主要代码如下:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
public
void
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
{
this.readerContext = readerContext;

Element root = doc.getDocumentElement();
//由BeanDefinitionParserDelegate协助完成xml到BeanDefinition的解释工作
BeanDefinitionParserDelegate delegate =
createHelper(readerContext, root);

preProcessXml(root);//空函数实现
//把Element解释为BeanDefinition,并注册
parseBeanDefinitions(root, delegate);
postProcessXml(root);//空函数
}


protected
void
parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
{
//判断节点是否属于命名空间http://www.springframework.org/schema/beans

if (delegate.isDefaultNamespace(root.getNamespaceURI()))
{
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;
String namespaceUri = ele.getNamespaceURI();

if (delegate.isDefaultNamespace(namespaceUri))
{
//对xml document的解释工作在这里完成
parseDefaultElement(ele, delegate);
}

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

else
{
//解释定制元素,例如aop、context等。
delegate.parseCustomElement(root);
}
}


private
void
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
{
//解释import标签

if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT))
{
importBeanDefinitionResource(ele);
}

else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT))
{
processAliasRegistration(ele);
}
//这里是真正的开始解释bean节点

else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT))
{
processBeanDefinition(ele, delegate);
}
}


protected
void
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
{

/** *//** *//** *//**把Element解释成GenericBeanDefinition(BeanDefinition的具体实现),并创建新的BeanDefinitionHolder,并把解释的definition、beanName、aliases封装进BeanDefinitionHolder*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//实现参看后面的parseBeanDefinitionElement方法分析

if (bdHolder != null)
{
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//对定制的一些配置进行装饰性解释,例如aop

try
{
//注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}

catch (BeanDefinitionStoreException ex)
{
……
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinition的注册过程,主要是把解释出来的BeanDefinition、bean名称缓存到内部容器中的过程,并且维护BeanDefinition的一致性。BeanDefination注册的关键代码如下:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
/**/
/*解释的过程主要完成对id、name、parent、lazy-init、singleton等属性的解释,并把相关属性设置到BeanDefinition中。接下来我们看看BeanDefinition的注册,即BeanDefinitionReaderUtils.registerBeanDefinition的实现:*/
public
static
void
registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

throws
BeanDefinitionStoreException
{

//注册BeanDefinition
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

//注册bean的别名
String[] aliases = definitionHolder.getAliases();

if (aliases != null)
{

for (int i = 0; i < aliases.length; i++)
{
registry.registerAlias(beanName, aliases[i]);
}
}
}

public
class
DefaultListableBeanFactory
extends
AbstractAutowireCapableBeanFactory

implements
ConfigurableListableBeanFactory, BeanDefinitionRegistry
{


/** *//** *//** *//**Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;


/** *//** *//** *//** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;


/** *//** *//** *//** Whether bean definition metadata may be cached for all beans */
private boolean configurationFrozen = false;

/** *//** *//** *//** Map of bean definition objects, keyed by bean name *///以ConcurrentMap存储BeanDefinition
private final Map beanDefinitionMap =
CollectionFactory.createConcurrentMapIfPossible(16);


/** *//** *//** *//** List of bean definition names, in registration order *///存储注册的beanName
private final List beanDefinitionNames = new ArrayList();


/** *//** *//** *//** Cached array of bean definition names in case of frozen configuration *///存储被冻结的beanName
private String[] frozenBeanDefinitionNames;


public void registerBeanDefinition(String beanName,
BeanDefinition beanDefinition)

throws BeanDefinitionStoreException
{


if (beanDefinition instanceof AbstractBeanDefinition)
{

try
{
((AbstractBeanDefinition) beanDefinition).validate();
}

catch (BeanDefinitionValidationException ex)
{
……
}
}


synchronized (this.beanDefinitionMap)
{
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

if (oldBeanDefinition != null)
{
//如果相同名字的BeanDefinition已经存在,且不允许覆盖,抛出异常。

if (!this.allowBeanDefinitionOverriding)
{
throw new BeanDefinitionStoreException(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);

resetBeanDefinition(beanName);
}
}


protected void resetBeanDefinition(String beanName)
{
// Remove the merged bean definition for the given bean, if already created.
clearMergedBeanDefinition(beanName);

// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).

synchronized (getSingletonMutex())
{//
destroySingleton(beanName);
}

// Reset all bean definitions that have the given bean as parent
// (recursively).

for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();)
{
String bdName = (String) it.next();

if (!beanName.equals(bdName))
{
BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(bdName);

if (beanName.equals(bd.getParentName()))
{
resetBeanDefinition(bdName);
}
}
}
}
spring中bean标签的解释代码一览:
parseBeanDefinitionElement方法分析
该方法主要针对bean标签进行解释处理,解释后的信息封装到GenericBeanDefinition中,然后把beanName、alias、GenericBeanDefinition封装到BeanDefinitionHolder中.
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
public
BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)
{

String id = ele.getAttribute(ID_ATTRIBUTE);//取得id属性

//取得name属性

String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

List aliases = new ArrayList();//aliase属性 例如<alias name="fromName" alias="toName"/>


if (StringUtils.hasLength(nameAttr))
{

//如果name属性存在,则把name的值分解,存储到aliases集合中

String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);

aliases.addAll(Arrays.asList(nameArr));

}


String beanName = id;//默认id的值作为beanName


if (!StringUtils.hasText(beanName) && !aliases.isEmpty())
{//如果id不存在,且aliases不为空,那么以aliases中的第一个作为beanName

beanName = (String) aliases.remove(0);


if (logger.isDebugEnabled())
{

logger.debug("No XML 'id' specified - using '" + beanName +

"' as bean name and " + aliases + " as aliases");

}

}



if (containingBean == null)
{


/**//*检查在一个文件中,beanName或者alias是否有重复的,如果有重复的报告错误,无重复,则把当前的beanName与alias记录到Set中*/

checkNameUniqueness(beanName, aliases, ele);

}


//对bean的详细解释,主要包括常见的class、parent、lazy-init、singleton等属性

AbstractBeanDefinition beanDefinition = 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,其规则如下:

如果beanDefinition存在className,则以"className#编号"或者"className"作为beanName;

如果beanDefinition不存在className,且beanDefinition存在parentName,则以"parentName$child#编号"或者"parentName$child"作为beanName;

如果beanDefinition不存在className,且beanDefinition存在factorybeanName,则以"factoryBeanName$created#编号"或者"factoryBeanName$created"作为beanName;

注意,编号是通过查询容器是否包含beanName,然后累加获得的*/

beanName = this.readerContext.generateBeanName(beanDefinition);

String beanClassName = 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 (Exception ex)
{

error(ex.getMessage(), ele);

return null;

}

}

String[] aliasesArray = StringUtils.toStringArray(aliases);

//最后封装为BeanDefinitionHoler返回

return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

}


return null;

}

public
AbstractBeanDefinition parseBeanDefinitionElement(


Element ele, String beanName, BeanDefinition containingBean)
{

String className = null;//解释class属性


if (ele.hasAttribute(CLASS_ATTRIBUTE))
{

className = ele.getAttribute(CLASS_ATTRIBUTE).trim();

}

String parent = null;


if (ele.hasAttribute(PARENT_ATTRIBUTE))
{//parent属性

parent = ele.getAttribute(PARENT_ATTRIBUTE);

}



try
{

//以bean的id作为参数封装到BeanEntry中;ParseState以Stack作为存储数据结构来存储Bean的解释状态

this.parseState.push(new BeanEntry(beanName));


//创建了GenericBeanDefinition,并为其设置parent=='parent',beanClass=='class',beanClassName属性

AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(

parent, className, this.readerContext.getBeanClassLoader());



if (ele.hasAttribute(SCOPE_ATTRIBUTE))
{//解释scope

bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));


if (ele.hasAttribute(SINGLETON_ATTRIBUTE))
{

error("Specify either 'scope' or 'singleton', not both", ele);

}

}


else if (ele.hasAttribute(SINGLETON_ATTRIBUTE))
{//singleton

bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?

BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);

}


else if (containingBean != null)
{

bd.setScope(containingBean.getScope());

}



if (ele.hasAttribute(ABSTRACT_ATTRIBUTE))
{//解释abstract

bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));

}


String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);//解释lazy-init


if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton())
{

// Just apply default to singletons, as lazy-init has no meaning for prototypes.

lazyInit = this.defaults.getLazyInit();

}

bd.setLazyInit(TRUE_VALUE.equals(lazyInit));


String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);//解释自动装配模式

bd.setAutowireMode(getAutowireMode(autowire));


String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);

bd.setDependencyCheck(getDependencyCheck(dependencyCheck));//解释依赖检查



if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE))
{

String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);//解释depends-on

bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS));

}


String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);


if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate))
{

String candidatePattern = this.defaults.getAutowireCandidates();


if (candidatePattern != null)
{

String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);

bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));

}

}


else
{

bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));

}



if (ele.hasAttribute(PRIMARY_ATTRIBUTE))
{

bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));

}



if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE))
{

String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);


if (!"".equals(initMethodName))
{

bd.setInitMethodName(initMethodName);

}

}


else
{


if (this.defaults.getInitMethod() != null)
{

bd.setInitMethodName(this.defaults.getInitMethod());

bd.setEnforceInitMethod(false);

}

}



if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE))
{

String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);


if (!"".equals(destroyMethodName))
{

bd.setDestroyMethodName(destroyMethodName);

}

}


else
{


if (this.defaults.getDestroyMethod() != null)
{

bd.setDestroyMethodName(this.defaults.getDestroyMethod());

bd.setEnforceDestroyMethod(false);

}

}



if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE))
{//解释工厂方法属性

bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));

}


if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE))
{//解释工厂bean属性

bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));

}


bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));


parseMetaElements(ele, bd);


/** *//**解释lookup-method(方法注入的一种),还记得吗,使用lookup-method能够覆盖bean标签指定的bean的抽象method(该method由method标签指定),主要针对singleton引用一个prototype的情形*/

parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

//解释replace-method(方法注入的一种)

parseReplacedMethodSubElements(ele, bd.getMethodOverrides());


parseConstructorArgElements(ele, bd);


/** *//**这里把解释出来的属性值,ref[RuntimeBeanReference]、list[ManagedList]、set[ManagedSet]、map、properties,封装到PropertyValue,

然后把PropertyValue加入到BeanDefinition*/

parsePropertyElements(ele, bd);

parseQualifierElements(ele, bd);


bd.setResource(this.readerContext.getResource());

bd.setSource(extractSource(ele));

return bd;

}
到此为止,spring IOC容器启动中的内部容器初始化部分基本分析完成。