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標籤的解析大同小異.