在上一篇文章中,分析了ApplicationContext容器的建立,加載資源文件,將資源文件讀取爲Document。spring將xml文件中的Bean註冊spring定義的BeanDefinition對象。在DefaultBeanDefinitionDocumentReader中對Document屬性的解析委託給BeanDefinitionParserDelegate這個代理類來實現的。node
DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法實現以下,首先獲取Document的根元素,接着調用doRegisterBeanDefinitions(root)進行註冊spring
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; //獲取根元素 Element root = doc.getDocumentElement(); //註冊BeanDefinition doRegisterBeanDefinitions(root); }
doRegisterBeanDefinitions(root)方法的實現以下:app
protected void doRegisterBeanDefinitions(Element root) { //獲取代理類 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //是否爲默認命名空間 if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); //是否有profile屬性 if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); //解析BeanDefinition parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
parseBeanDefinitions(root, this.delegate)方法是解析根源素下定義的每個bean。首先,獲取節點List。其次,判斷每一個元素是否爲默認的命名空間中的元素,而後交給不一樣的方法去解析,具體的實現以下:post
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //若是根元素爲默認命名空間中的元素 if (delegate.isDefaultNamespace(root)) { //獲取字元素List 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); } }
下面,咱們首先看spring默認命名空間元素的解析過程,parseDefaultElement(ele, delegate)方法的實現以下:ui
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)) { // recurse 循環調用 doRegisterBeanDefinitions(ele); } }
import元素是引入其餘的配置文件,resource屬性是配置文件的路徑,importBeanDefinitionResource(ele)方法的實現以下,省略了異常處理代碼:this
protected void importBeanDefinitionResource(Element ele) { //獲取resource屬性值,即其餘配置文件的路徑 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); // 解析路徑,如"${user.dir}" 這樣的路徑是從在propertie文件中加載的 location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // 判斷location 是絕對路徑仍是相對路徑 boolean absoluteLocation = false; absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); // 絕對路徑 if (absoluteLocation) { //調用loadBeanDefinitions(location, actualResources)方法解析此配置文件 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); } } //相對路徑 else { int importCount; Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { //調用loadBeanDefinitions(relativeResource)方法解析此配置文件 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } } } //廣播Import元素處理事件 Resource[] actResArray = actualResources.toArray(new Resource[0]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
下面介紹alias元素的方法,processAliasRegistration(ele)方法的實現以下:spa
protected void processAliasRegistration(Element ele) { //獲取name屬性 String name = ele.getAttribute(NAME_ATTRIBUTE); //獲取alias屬性 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { //調用SimpleAliasRegistry類的registerAlias(name, alias)進行註冊 getReaderContext().getRegistry().registerAlias(name, alias); getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } }
在SimpleAliasRegistry中定義了aliasMap來存儲alias和name的關係,具體實現以下:代理
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16); public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { //若是alias和name相等,將此關係移除 if (alias.equals(name)) { this.aliasMap.remove(alias); } else { //先從aliasMap獲取key爲alias的beanName String registeredName = this.aliasMap.get(alias); if (registeredName != null) { //若是已存在,return if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } //若是不存在,判斷alias是否能夠繼承,默認是true if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } //檢查是否存在循環依賴 checkForAliasCircle(name, alias); //註冊alias和name this.aliasMap.put(alias, name); } } }
processBeanDefinition(ele, delegate)實現以下:code
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //解析bean元素,建立BeanDefinitionHolder實例 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //完成必須的裝配 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 進行最終的註冊bean BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
bean元素的解析和註冊相對複雜,在下一節中討論。xml