Spring Ioc 源码分析(一)- XML 解析

注 :源码对应版本为 4.2.8.RELEASEjava

引入Spring依赖的时候,是否发现spring依赖有spring-beans和spring-context两个jar,spring容器的顶层接口BeanFactory在spring-beans,而咱们经常使用的ApplicationContext则在spring-context中定义。目前的认知是,ApplicationContext是在BeanFactory的基础上,提供了不少容器上下文的功能。那么到底BeanFactory提供了哪些功能,ApplicationContext在这些功能的基础上又额外提供了哪些上下文功能,其中的实现原理是什么?node

1、BeanFactory

首先抛开ApplicationContext,咱们单独来看一下spring-beans模块中提供了哪些接口和功能:web

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

	<bean class="lujing.sample.bean.TargetBean" />
</beans>
public class XmlBeanFacotyTest {

	public static void main(String[] args) {

        //指定xml文件
		Resource resource = new ClassPathResource("spring/applicationContext-beanFactory.xml");
        //实例化一个XmlBeanFactory
		XmlBeanFactory beanFactory = new XmlBeanFactory(resource);

        //这样就能够工做啦,能够getBean了
		TargetBean targetBean = beanFactory.getBean(TargetBean.class);
		System.out.println(targetBean.getName());
	}
}

查看XmlBeanFactory的源码能够看到,也比较简单:spring

@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);


	/**
	 * Create a new XmlBeanFactory with the given resource,
	 * which must be parsable using DOM.
	 * @param resource XML resource to load bean definitions from
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

	/**
	 * Create a new XmlBeanFactory with the given input stream,
	 * which must be parsable using DOM.
	 * @param resource XML resource to load bean definitions from
	 * @param parentBeanFactory parent bean factory
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

}

其实就是2个核心类,分别是 DefaultListableBeanFactory  和  XmlBeanDefinitionReader ,spring自己标识了XmlBeanFactory废弃,取而代之使用 DefaultListableBeanFactory 和 XmlBeanDefinitionReader,因此以上代码能够写成:设计模式

public class BeanFactoryTest {

	public static void main(String[] args) {

		Resource resource = new ClassPathResource("spring/applicationContext-beanFactory.xml");
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(null);
		new XmlBeanDefinitionReader(beanFactory).loadBeanDefinitions(resource);

		TargetBean targetBean = beanFactory.getBean(TargetBean.class);
		System.out.println(targetBean.getName());
	}
}

显而易见,spring中xml解析是由 XmlBeanDefinitionReader 来完成的。剥离了xml这一层具体的实现(也能够有基于Annotation的实现等)缓存

2、XmlBeanDefinitionReader 

从上述代码中能够看到,xml到解析工做经过 loadBeanDefinitions方法完成:安全

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
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());
		}

        //这里使用ThreadLocal一方面为了线程安全考虑,另外一方面提供存储
        //使用
        //	private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
		//	new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently 
        //  being loaded");
        //而不用 Set<EncodedResource>  currentResources = new HashSet<EncodedResource>(4);
        //是由于该方法可能会被多线程调用。为了记录当前正在解析的Resource文件
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
            //初始化set并设置线程上文
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}

        //利用Set的add方法,判断重复的定义
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
                //继续调用解析
				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();
			}
		}
	}

从上面的代码中能够看到,该方法主要作了:网络

利用线程上下文值,记录当前线程正在解析的xml文件。检查import标签可能引入的循环解析问题多线程

从这个方法中咱们也能够借鉴两种经常使用的写法:架构

1. 关于ThreadLocal的用法,在使用get(),set()使用完成之后,必需要在finally代码块中 remove()掉

2. loadBeanDefinitions 和 doLoadBeanDefinitions的方法命名,咱们发现spring中这类命名特别多。do开头的方法每每是正真的业务实现,一些外围处理都环绕在外面。这样的写法看起来真的特别舒服,一层一层的,极大的减小了代码的理解复杂度。同时也为扩展提供了很好的架构。通常spring中do开头的方法都是protected的,显然告诉spring的使用者,这是一个扩展点。这也是设计模式中 “模板模式”很好的体现。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
            //生成XML Document 文档对象
			Document doc = doLoadDocument(inputSource, resource);
            //注册Bean定义
			return registerBeanDefinitions(doc, resource);
		}
		//catch 各类异常,统一包装为 XmlBeanDefinitionStoreException
        //这里就不贴代码了
	}

 生成XML文档对象的时候,使用了DocumentLoader实现类来完成,底层主要是利用JAXP完成从xml解析问Document对象: 

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		  //private DocumentLoader documentLoader = new DefaultDocumentLoader();
          return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}

Bean的解析使用BeanDefinitionDocumentReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

3、DocumentLoader

spring底层经过JAXP技术,完成从xml到Document对象的解析。

在xml解析中有一点比较重要,就是xml的验证,它主要分为DTD验证和XSD验证两种。不管哪种验证,java都须要加载相应的DTD或XSD文件,默认是直接从xml中对应的地址下载,这里是 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

	<bean class="lujing.sample.bean.TargetBean" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"  "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
        <bean class="lujing.sample.bean.TargetBean" />
</beans>

为了不这样的网络请求,jaxp提供了EntityResolver方法,spring就是经过实现该接口,实现了从classpath中加载对应的文件。

protected EntityResolver getEntityResolver() {
		if (this.entityResolver == null) {
			// Determine default EntityResolver to use.
			ResourceLoader resourceLoader = getResourceLoader();
			if (resourceLoader != null) {
				this.entityResolver = new ResourceEntityResolver(resourceLoader);
			}
			else {
				this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
			}
		}
		return this.entityResolver;
	}

4、BeanDefinitionDocumentReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //建立 BeanDefinitionDocumentReader 对象
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //记录调用BeanDefinitionDocumentReader以前已经解析完成的 Bean 数量
        //getRegistry返回的是咱们建立的 DefaultListableBeanFactory
		int countBefore = getRegistry().getBeanDefinitionCount();
        //解析
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //如今的Bean数量减去以前的数量,就是本次加载的Bean数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

 建立BeanDefinitionDocumentReader就是根据设定的class实例化,默认实现是org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader

protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
		return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
	}

 具体的BeanDefinitionDocumentReader经过registerBeanDefinitions方法完成。

建立XmlReaderContext主要是把XmlBeanDefinitionReader中设置的NamespaceHandlerResolver传递过去,在解析的时候须要用到。这也是设计模式中“门面模式”的体现。真正的逻辑都是委托给别的核心组件来完成。

public XmlReaderContext createReaderContext(Resource resource) {
		return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
				this.sourceExtractor, this, getNamespaceHandlerResolver());
	}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //设置解析上下文
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
        //获取根节点
		Element root = doc.getDocumentElement();
        //调用真正的解析方法
		doRegisterBeanDefinitions(root);
	}

下面是真正的解析核心方法了,方法仍旧是一个模版方法,对最外层的beans节点,作了过滤

解析代码的时候都用到了 delegate.isDefaultNamespace(element)方法,该方法的用处就是判断元素节点是否是 beans 命名空间下的 节点,或者是 自定义节点如 <tx:annotation-driver> 。spring判断的依据就是节点的namespace是否是固定的 http://www.springframework.org/schema/beans,spring在xml解析的时候,设置了 namespaceAware参数为true,每一个节点均可以取到 namespace。

protected void doRegisterBeanDefinitions(Element root) {
		// 解析一个<beans/>节点,任何嵌套的beans标签都会从新调用一次这个方法
        //每一个beans节点都有一个BeanDefinitionParserDelegate,同时再实例化的时候指定 parent
        //这里主要考虑 传播和保存 benas节点中 default-*(default-init-method等)值
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

        //profile机制只对标准beans定义的生效,对于自定义标签订义的beans不生效
		if (this.delegate.isDefaultNamespace(root)) {
            //读取profile属性值,用于区分如生产、测试等
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            //未指定profile默认bean都是生效的
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                //若是指定了 profiles 且 不符合 environment定义的 激活的 profiles ,那么直接忽略
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}
         
        //扩展点方法,默认实现为空
		preProcessXml(root);
 
        //利用BeanDefinitionParserDelegate真正的解析节点
		parseBeanDefinitions(root, this.delegate);

        //扩展点方法,默认实现为空
		postProcessXml(root);

		this.delegate = parent;
	}

4.1  BeanDefinitionParserDelegate

里面使用了BeanDefinitionParserDelegate委派处理:

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 {
                        //自定义标签解析,如常见的 <tx:annotation-driven/>
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
        //是自定义节点,调用自定义节点的解析方式,这里的考虑点仍是 自定义的 beans 标签,好比 <coustom:beans/>
		else {
			delegate.parseCustomElement(root);
		}
	}
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);
		}
	}

import标签其实就是循环解析xml文件,这里就不贴代码了;alias标签其实就是注册别名,也很是简单。

5、自定义标签解析

spring 的 自定义标签机制是 spring的扩展的基础,众多功能如context,webmvc,transaction都使用自定义标签,方便用户再极简配置就能享受强大的功能。如 bean扫描<context:component-scan base-package=""/>,事务的<tx:annotation-driven/>等

public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}

	public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取命名空间
		String namespaceUri = getNamespaceURI(ele);
        //利用命名空间获得一个自定义解析器 NamespaceHandler 
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
        //自定义解析器的 parse 方法
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

从上面的代码能够看到,自定义解析大概分为3步:

1. 获取自定义标签的 namespaceUri ,用的是  node.getNamespaceURI(); ,以<tx:annotation-driven/>为例就是: http://www.springframework.org/schema/tx

xmlns:tx="http://www.springframework.org/schema/tx"

2. 利用 NamespaceHandlerResolver 的 resolve 方法实例化一个 NamespaceHandler 

public interface NamespaceHandlerResolver {

	/**
	 * 根据namespaceUri实例化一个NamespaceHandler对象
	 */
	NamespaceHandler resolve(String namespaceUri);

}

这里使用的是 DefaultNamespaceHandlerResolver 实现类:

public NamespaceHandler resolve(String namespaceUri) {
        //加载 namespaceUri=namespaceHandler 对应表
		Map<String, Object> handlerMappings = getHandlerMappings();
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
        // 若是是NamespaceHandler对象就直接返回。这里对象的判断是,前面若是有该标签出现过,这里直接缓存对象了
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
        //NamespaceHandler的完整类路径处理
		else {
			String className = (String) handlerOrClassName;
			try {
				Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                //类型检查
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                //init方法,注意这个方法很重要,是用户扩展点中很重要的一点
				namespaceHandler.init();
                //覆盖原来的,避免屡次实例化
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "] not found", ex);
			}
			catch (LinkageError err) {
				throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
						namespaceUri + "]: problem with handler class file or dependent class", err);
			}
		}
	}

能够看到 getHandlerMappings()方法读取了全部的 META-INF/spring.handlers" 文件。仍是以 tx为例,在spring-tx.jar 能够看到 META-INF/spring.handlers 文件的内容: 

http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

在上面的代码中咱们能够看到,init()方法是生命周期方法,用于初始化。

public class TxNamespaceHandler extends NamespaceHandlerSupport {

	static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";

	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";


	static String getTransactionManagerName(Element element) {
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}


	@Override
	public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

}

init()方法基本上是固定的写法,就是为每一个标签订义一个 BeanDefinitionParser 

6、Bean标签的解析

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.java
/**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //利用delegate获取一个BeanDefinitionHolder对象,包含了beanName,alias, BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
            //装饰BeanDefinitionHolder 
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 注册到容器中,这里就是 DefaultListableBeanFactory
				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));
		}
	}
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.java
/**
     *  解析<bean>节点,若是解析错误返回null.错误被通知到 
     *  org.springframework.beans.factory.parsing.ProblemReporter
     */
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

 简单的作了一个适配:

/**
     *  解析<bean>节点,若是解析错误返回null.错误被通知到 
     *  org.springframework.beans.factory.parsing.ProblemReporter
     */
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //读取id属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
        //读取name属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        //处理name属性为别名
		List<String> aliases = new ArrayList<String>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
        
        //默认是beanName为id属性,没有id属性使用第一个beanName做为beanName
		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) {
            //校验beanName的惟一性,在同一个Beans标签下面不能重复
			checkNameUniqueness(beanName, aliases, ele);
		}

		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
            //若是没有指定beanName使用,使用spring规则生成beanName
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						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);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

        //出错的时候 error 要用到
		this.parseState.push(new BeanEntry(beanName));

        //class属性
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
            //parent属性
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
            //自定义的bean标签返回的是 GenericBeanDefinition 
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            //解析各类属性 lazy-init,init-method 等
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

            //description节点直接读
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
           
            //解析meta
			parseMetaElements(ele, bd);
            //解析lookup-method
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析replaced-method
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析构造函数参数
			parseConstructorArgElements(ele, bd);
            //解析property
			parsePropertyElements(ele, bd);
            //解析qualifier
			parseQualifierElements(ele, bd);
            
			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

终于看到了对全部属性元素的解析,其余都是一些相对简单的解析,最难的就是property节点的解析:

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
            //遍历子节点
            //isCandidateElement: 
            //(node instanceof Element && (isDefaultNamespace(node) || !isDefaultNamespace(node.getParentNode())));
            //标签名称是property
            //调用parsePropertyElement解析
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
				parsePropertyElement((Element) node, bd);
			}
		}
	}
相关文章
相关标签/搜索