1. 程式人生 > >spring原始碼深度解析(筆記二)--預設標籤的解析

spring原始碼深度解析(筆記二)--預設標籤的解析

預設標籤的解析是在parseDefaultElement中:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele); //處理import標籤
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);    //處理alias標籤
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
//處理bean標籤 } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); //處理beans標籤 } }

分析對bean標籤的解析及註冊:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { 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));
} }

1,首先委託BeanDefinitionDelegate類的parseBeanDefinitionElement方法進行元素解析,返回BeanDefinitionHolder類例項bdHolder,此時bdHolder例項中已經包含了配置檔案中的各種屬性,如class、name、id、alias.

2,當返回的bdHolder不為空時,若存在預設標籤的子節點下再有自定義屬性,還需再次對自定義標籤進行解析.

3,註冊bdHolder

4,發出響應事件,通知相關的監聽器,這個bean已經載入完成.

以下是每一步的具體分析(程式碼多有刪減,只保留關鍵處):

===========================================================

一,返回包含各種配置屬性的BeanDefinitionHolder例項bdHolder

public class BeanDefinitionParserDelegate {
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		//解析id屬性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		//解析name屬性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		//分隔name屬性......
		
		//進一步解析其他屬性並統一封裝到GenericBeanDefinition型別的例項中
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		
//若檢測到bean沒有指定beanName,那麼使用預設規則為此bean生成beanName
		if (containingBean != null) {
			beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
		}
		else {
			beanName = this.readerContext.generateBeanName(beanDefinition);
			
		//將獲取到的資訊封裝到BeanDefinitionHolder
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

public class BeanDefinitionParserDelegate {
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
	this.parseState.push(new BeanEntry(beanName));
	//解析class屬性
	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}

	//解析parent屬性
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}
	//建立用於承載各種屬性的AbstractBeanDefinition子類GenericBeanDefinition的例項
	AbstractBeanDefinition bd = createBeanDefinition(className, parent);

	//硬編碼解析預設bean的各種屬性
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
	//提取description
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

	//解析元資料
		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;


BeanDefinition是AbstractBeanDefinition的介面.

spring通過BeanDefinition將配置檔案中的bean配置資訊轉換為容器的內部表示,並將這些BeanDefinition註冊到BeanDefinitionRegistry中。

spring的BeanDefinitionRegistry就像是spring配置資訊的記憶體資料庫,主要是以map的形式儲存;後續操作直接從BeanDefinitionRegistry中讀取配置資訊.

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) {
		return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
	}

public class BeanDefinitionReaderUtils {
public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) {

	GenericBeanDefinition bd = new GenericBeanDefinition();
	bd.setParentName(parentName);
	if (className != null) {
		if (classLoader != null) {
			bd.setBeanClass(ClassUtils.forName(className, classLoader));  //載入位元組碼檔案
		}
		else {
			bd.setBeanClassName(className);
		}
	}
	return bd;
}

有了承載各種屬性的BeanDefinition例項了,可以進行各種屬性的解析了.

scope、singleton、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、

factory-bean屬性等.

meta屬性用作額外的宣告;

lookup-method獲取器注入,把一個方法宣告為返回某種型別的bean,但實際要返回的bean是在配置檔案裡面配置.

replace-method方法替換,可以在執行時用新的方法替換現有的方法.

=============================================

解析預設標籤中的自定義型別屬性:

public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
	BeanDefinitionHolder finalDefinition = definitionHolder;
	NamedNodeMap attributes = ele.getAttributes();

	//遍歷所有屬性,看看是否有適用於修飾的屬性
	for (int i = 0; i < attributes.getLength(); i++) {
		Node node = attributes.item(i);
		finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
	}

	NodeList children = ele.getChildNodes();
	//遍歷所有的子節點,看看是否有適用於修飾的子元素
	for (int i = 0; i < children.getLength(); i++) {
		Node node = children.item(i);
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
		}
	}
	return finalDefinition;
}

public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
	//獲得自定義標籤的名稱空間
	String namespaceUri = getNamespaceURI(node);
	//對於非預設標籤的進行修飾
	if (!isDefaultNamespace(namespaceUri)) {
		//根據名稱空間找到對應的處理器
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler != null) {
			//進行修飾
			return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
		}
	}
	return originalDef;
}

====================================================

註冊解析的BeanDefinition

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

public class BeanDefinitionReaderUtils {
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry){
	//使用beanName做唯一標識註冊
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
	//註冊所有別名
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			//註冊前最後一次校驗,校驗methodOverrides
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			//拋異常
		}
	}

	//處理已經註冊beanName的情況
	//記錄beanName
	this.beanDefinitionNames.add(beanName);
	this.frozenBeanDefinitionNames = null;
	//註冊beanDefinition
	this.beanDefinitionMap.put(beanName, beanDefinition);
resetBeanDefinition(beanName); //重置所有beanName對應的快取
}

public class SimpleAliasRegistry implements AliasRegistry {
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
public void registerAlias(String name, String alias) {
	if (alias.equals(name)) {
		this.aliasMap.remove(alias); //若beanName與alias相同的話不記錄alias,並刪除對應的alias
	}
	else {
		String registeredName = this.aliasMap.get(alias);
		if (registeredName != null) {
			if (registeredName.equals(name)) {
				return;
			}
			if (!allowAliasOverriding()) {
			//若alias不允許被覆蓋則拋異常
			}
		}
		checkForAliasCircle(name, alias);
		//註冊alias
		this.aliasMap.put(alias, name);
	}
}

====================================================

通知監聽器解析及註冊完成

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

此實現只為擴充套件,當需要對註冊BeanDefinition事件進行監聽時,可以通過註冊監聽器的方式將處理邏輯寫入監聽器中.

=================================

=================================

alias、import及beans標籤和bean標籤的解析大同小異.