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

spring技术内幕笔记:IoC容器初始化过程(2)- BeanDefinition的载入

2017-07-12 22:25 751 查看
Spring版本:4.3.8.RELEASE

BeanDefinition载入过程,相当于把定义的BeanDefinition在IoC容器中转换成一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入功能的实现,就是通过对其持有的BeanDefinition进行的各种相关操作完成的。这些BeanDefinition数据在IoC容器中通过HashMap来保存和维护。

从DefaultListableBeanFactory的设计入手,看一下IoC容器载入BeanDefinition的过程。

1、FileSystemXmlApplicationContext

从FileSystemXmlApplicationContext开始,在FileSystemXmlApplicationContext的构造函数FileSystemXmlApplicationContext(String[] configLocations,
boolean refresh, ApplicationContext parent)中调用了refresh方法

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

public FileSystemXmlApplicationContext() {
}

public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}

/**
* 构造函数:需要传入XML资源文件的路径
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

/**
* 构造函数:传入多个资源文件
*/
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}

/**
* 构造函数
* @param configLocations 资源文件数组
* @param parent 双亲IoC容器
*/
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}

/**
* 构造函数
* @param configLocations 资源文件路径
* @param refresh 是否调用refresh方法载入BeanDefinition
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}

/**
* 构造函数
* @param configLocations 资源文件路径
* @param refresh 是否调用refresh方法载入BeanDefinition
* @param parent 双亲IoC容器
* @throws BeansException
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();//分析容器初始化的一个重要入口
}
}

/**
* 通过资源文件路径获取Resource对象,返回的是一个FileSystemResource对象,通过这个对象可以进行相关I/O操作,完成BeanDefinition定位
* @param path 资源文件路径
* @return Resource spring中的资源对象
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}

}
refresh()方法,启动了对BeanDefinition资源定位的过程,由AbstractApplicationContext实现
2、AbstractApplicationContext

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// 调用obtainFreshBeanFactory()方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//调用了refreshBeanFactory()方法
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

//由子类AbstractRefreshableApplicationContext实现
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
refresh()方法中,调用了obtainFreshBeanFactory()方法,obtainFreshBeanFactory()方法又调用了refreshBeanFactory方法,在AbstractApplicationContext中,该方法是一个抽象方法,具体的实现由AbstractApplicationContext的子类AbstractRefreshableApplicationContext来实现。
3、AbstractRefreshableApplicationContext

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

/**
* AbstractRefreshableApplicationContext中实现的refreshBeanFactory()方法
*
* @throws BeansException
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果已经建立了BeanFactory,销毁并关闭BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//构造了一个BeanFactory,这里使用DefaultListableBeanFactory实现
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//载入BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

/**
* 创建DefaultListableBeanFactory的地方
* getInternalParentBeanFactory()的具体实现可以参看AbstractApplicationContext的实现
*
* @return
*/
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

/**
* 抽象方法,载入BeanDefinition,由子类AbstractXmlApplicationContext实现
*
* @param beanFactory
* @throws BeansException
* @throws IOException
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
}

loadBeanDefinitions方法由AbstractXmlApplicationContext类实现

4、AbstractXmlApplicationContext
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader对象,通过回调设置到BeanFactory中,beanFactory使用的也是DefaultListableBeanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
//设置ResourceLoader,因为DefaultResourceLoader是父类,所以this可以直接被调用
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//启动Bean定义信息载入的过程,委托给BeanDefinitionReader完成
initBeanDefinitionReader(beanDefinitionReader);
//XmlBeanDefinitionReader对象加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}

protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating);
}

/**
* 载入BeanDefinition
* @param reader
* @throws BeansException
* @throws IOException
*/
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//以Reource的方式获取配置文件的资源位置
Resource[] configResources = getConfigResources();
if (configResources != null) {
//调用loadBeanDefinitions方法,该方法在XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中已经实现
reader.loadBeanDefinitions(configResources);
}
//以string方式获取配置文件的位置
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

}
初始化FileSystemXmlApplicationContext的过程中是通过调用IoC容器的refresh来启动整个BeanDefinition的载入过程的,这个初始化是通过定义的XmlBeanDefinitionReader对象来完成的,使用的Ioc容器是DefalutListableBeanFactory,具体的Resource载入在XmlBeanDefinitionReader读入BeanDefinition时实现,这里使用的是XML的方式定义,因此使用XmlBeanDefinitionReader载入。如果是其他的方式,需要使用其他的BeanDefinitionReader。loadBeanDefinitions已在XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader实现。
5、AbstractBeanDefinitionReader

public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
//如果Resource为空,停止BeanDefinition的载入,否则启动载入BeanDefinition的过程
Assert.notNull(resources, "Resource array must not be null");
//对载入Bean的数量进行统计
int counter = 0;
//遍历整个Resource集合,从每个集合中载入所有的BeanDefinition
for (Resource resource : resources) {
//loadBeanDefinitions方法是一个接口方法,在XmlBeanDefinitionReader中有具体的实现
counter += loadBeanDefinitions(resource);
}
return counter;
}
}


在AbstractBeanDefinitionReader的loadBeanDefinitions方法中,又调用了XmlBeanDefinitionReader的loadBeanDefinitions方法。

6、XmlBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//(1)入口
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//调用载入以XML形式的BeanDefinition的方法,并使用Resource对象创建EncodedResource对象
return loadBeanDefinitions(new EncodedResource(resource));
}

/**
* (2)载入以XML形式的BeanDefinition的方法
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//获取资源对象set集合
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//将当前的资源对象加入set集合
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取资源对象的输入流,得到XML文件
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//创建InputSource准备进行读取
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
//设置编码
inputSource.setEncoding(encodedResource.getEncoding());
}
//具体的读取过程在doLoadBeanDefinitions方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//移除已经读取过的资源对象
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
/**
* (3)具体载入BeanDefinition的方法
*  从特定的XML文件中实际载入BeanDefinition的地方
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//取得XML文件的Document对象
Document doc = doLoadDocument(inputSource, resource);
//启动的是对BeanDefinition解析的详细过程,会使用到spring的bean配置规则
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

/**
* (4)BeanDefinition解析的详细过程
* 按照Spring的Bean语义要求进行解析资源文件并转换为内部的数据结构BeanDefinition
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建BeanDefinitionDocumentReader对XML形式的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//具体的解析过程在registerBeanDefinitions方法中完成,该方法在DefaultBeanDefinitionDocumentReader中有实现
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//对载入Bean的数量进行统计
return getRegistry().getBeanDefinitionCount() - countBefore;
}

/**
* (5)创建BeanDefinitionDocumentReader对象
*
*/
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
//使用DefaultBeanDefinitionDocumentReader对XML形式的BeanDefinition进行解析
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;

}
BeanDefinition的载入分成两部分,首先通过调用XML的解析器得到Document对象,此时这些Document对象并没有按照Spring的Bean规则进行解析,在完成通用的XML解析以后,才是按照Spring 并没有按照Spring的Bean规则进行解析,在完成通用的XML解析以后,才是按照Spring Bean规则进行解析的地方,这个过程在documentReader中实现,使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader。
7、DefaultBeanDefinitionDocumentReader

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
/**
* (1)根据XML的Document对象,解析为BeanDefinition
*/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取根节点
Element root = doc.getDocumentElement();
//注册每一个BeanDefinition
doRegisterBeanDefinitions(root);
}

/**
* (2)根据根节点注册每一个BeanDefinition
*/
protected void doRegisterBeanDefinitions(Element root) {
//用于解析BeanDefinition的委托类
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//在开始处理bean定义之前,允许XML通过处理任何自定义元素类型进行扩展
preProcessXml(root);
//从根元素开始解析
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);

this.delegate = parent;
}

/**
* (3)从根元素开始解析BeanDefinition
* @param root the DOM root element of the document
*/
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);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

/**
* (4)解析默认的元素(import、alias、bean、beans)
*/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//import
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}//alias
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}//bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//处理元素
processBeanDefinition(ele, delegate);
}//beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归
doRegisterBeanDefinitions(ele);
}
}

/**
* (5)处理给定的Element元素,解析BeanDefinition并注册
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/* BeanDefinition的解析结果由BeanDefinitionHolder来持有,BeanDefinitionHolder是BeanDefinition的封装类,封装了
* BeanDefinition的名字和别名,用它来完成向IoC容器的注册
* 解析过程是由BeanDefinitionParserDelegate来实现,根据XML元素信息对Spring的bean规则进行解析
*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 向IoC容器注册解析得到的BeanDefnition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 注册完成后,发送消息
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

}
BeanDefinitionHolder除了持有BeanDefinition对象外,还持有其他与BeanDefinition的使用相关的信息,比如Bean的名字、别名集合等。这个解析过程是由BeanDefinitionParserDelegate来实现,这个类包含了对各种Spring Bean定义规则的处理,把元素的值从XML文件读出,设置到生成的BeanDefinitionHolder中。

8、BeanDefinitionParserDelegate

public class BeanDefinitionParserDelegate {
/**
* (1)解析XML元素
*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}

/**
* (2)解析元素的详细过程,并返回BeanDefinitionHolder对象
*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//获取<bean>元素中定义的id、name和aliase属性的值
String id = ele.getAttribute(ID_ATTRIBUTE);//id
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//name
//aliases
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

String beanName = 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);
}
//引发对Bean元素的详细解析
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 = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
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);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}

/**
* (3)对BeanDefinition定义元素的处理,具体生成BeanDefinition的地方
*/
上面是对Bean元素进行解析的过程,也就是BeanDefinition依据XML的<bean>定义被创建的过程,BeanDefinition可以看成是对<bean>的抽象,封装的数据大多都是

与<bean>定义相关的。
(1)以解析属性Property的方法为例,看一下整个BeanDefinition载入过程

/**
* 对指定Bean元素的<property>子元素集合进行解析
*/
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
//获取元素下所有的节点
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
//判断是<property>元素后对<property>元素进行解析
parsePropertyElement((Element) node, bd);
}
}
}

/**
* 解析<property>元素
*/
public void parsePropertyElement(Element ele, BeanDefinition bd) {
//获取<property>的name属性
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
//如果同一个Bean中已经有同名的property存在,则不进行解析,也就是同一个Bean中有相同的property,起作用的是第一个
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
//解析<property>值的地方,解析结果会封装到PropertyValue中,然后设置到BeanDefinitionHolder中
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}

/**
* 获取<property>元素的值
*/
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";

// Should only have one child element: ref, value, list, etc.
NodeList nl = ele.getChildNodes();//获取子节点,应该只有一个子元素,ref、value、list等
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
// Child element is what we're looking for.
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
//是否有ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
//是否有value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
//如果是ref属性
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
//创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref信息
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}//如果是value
else if (hasValueAttribute) {
//创建TypedStringValue对象,封装value信息
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}//如果还有子元素,触发对子元素的解析
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
这里是对property子元素解析的过程,Array、List、Set等各种元素都在这里进行解析,生成对应的数据对象,比如ManagedList、ManagedSet等,这些Managed类是Spring对具体的BeanDefinition的数据封装,具体解析方法在BeanDefinitionParserDelegate类中也都能找到。

(2)对<property>元素解析的过程

/**
* 解析<property>元素的子元素
*/
public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
return parsePropertySubElement(ele, bd, null);
}

/**
* Parse a value, ref or collection sub-element of a property or
* constructor-arg element.
* @param ele subelement of property element; we don't know which yet
* @param defaultValueType the default type (class name) for any
* {@code <value>} tag that might be created
*/
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
//如果元素没有使用spring默认命名空间,调用自定义元素解析方法
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {//如果是<bean>元素
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in a parent context.
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean', 'local' or 'parent' is required for <ref> element", ele);
return null;
}
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {//<idref>元素
return parseIdRefElement(ele);
}
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {//<value>元素
return parseValueElement(ele, defaultValueType);
}
else if (nodeNameEquals(ele, NULL_ELEMENT)) {//<null>元素
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {//<array>元素
return parseArrayElement(ele, bd);
}
else if (nodeNameEquals(ele, LIST_ELEMENT)) {//<list>元素
return parseListElement(ele, bd);
}
else if (nodeNameEquals(ele, SET_ELEMENT)) {//<set>元素
return parseSetElement(ele, bd);
}
else if (nodeNameEquals(ele, MAP_ELEMENT)) {//<map>元素
return parseMapElement(ele, bd);
}
else if (nodeNameEquals(ele, PROPS_ELEMENT)) {//<props>元素
return parsePropsElement(ele);
}
else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
parseListElement为例:
/**
* 解析<list>元素
*/
public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes();
ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
target.setSource(extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(parseMergeAttribute(collectionEle));
//具体的解析过程
parseCollectionElements(nl, target, bd, defaultElementType);
return target;
}
/**
* 解析集合元素的具体过程
*/
protected void parseCollectionElements(
NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
//遍历所有的元素节点
for (int i = 0; i < elementNodes.getLength(); i++) {
Node node = elementNodes.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
//加入到target中,target是一个ManagedList,同时触发对下一层的调用
target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
}
}
}


经过逐层解析,在XML文件中定义的BeanDefinition就被整个载入到了IoC容器中,并在容器中建立的数据映射。在IoC容器中建立的对应的数据结构以AbstractBeanDefinition

为入口,让IoC容器执行索引、查询和操作。

经过以上的载入过程,IoC容器大致完成了管理bean对象的数据准备工作,但是,现在在IoC容器中存在的还只是静态配置信息,要完全发挥容器的作用,还需要完成数据向容器的注册。

整体的流程:

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