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);
			}
		}
	}
相關文章
相關標籤/搜索