【超詳細的Spring源碼分析 —— 05 Spring對於Bean管理的核心組件源碼分析 - 註冊Bean Definition】

在上一章中,我留了一個 "BeanDefinition註冊到registry" 的尾巴還沒分析,這邊我把代碼入口從新放到下面,以便於回顧:java

/** * 經過解析器delegate去處理給定的bean element, 並解析出相應的bean Definition, 註冊到工廠中 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 經過delegate解析bean定義, 獲取到一個BeanDefinitionHolder實例
    // 這個實例, 其實就表明了xml文件中的一個完整的bean標籤對應的Bean Definition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    
    // 若是bdHolder不爲空, 說明解析成功了, 以後就是註冊環節了
    // 註冊環節咱們留着在下一篇中詳細展開
    if (bdHolder != null) {
    	bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    	try {
            // 註冊最終的BeanDefinition到工廠
            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));
    }
}
複製代碼

咱們要關注的是:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());緩存

1、註冊最終的BeanDefinition到工廠

要註冊BeanDefinition到工廠,首先咱們得獲取到工廠,這裏是經過讀取器上下文來獲取到的 getReaderContext().getRegistry()ide

還記得咱們第四章分析的:建立讀取器上下文的代碼麼,讀取器上下文內部是封裝了讀取器實例的,這就意味着咱們可以經過上下文獲取到讀取器。工具

緊接着,咱們在第一章分析的,建立讀取器時會傳入一個 registry 類型的參數,所以經過讀取器咱們又可以獲取到 registry。ui

所以,咱們就可以經過讀取器上下文獲取到 registry。this

BeanDefinitionReaderUtils.registerBeanDefinition()spa

這裏是調用了一個工具類來實現註冊的流程線程

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    // 獲取到Bean的惟一標識
    String beanName = definitionHolder.getBeanName();
    // 重點!!!!
    // 將 bean 定義真正註冊到 Bean 工廠中
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    // 若是存在別名, 那麼會註冊別名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
    	for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
    	}
    }
}
複製代碼

咱們接着深刻到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 這部分的邏輯:debug

因爲對於 registry 的實現是採用的 —— DefaultListableBeanFactory,所以咱們看看這個類對於 registerBeanDefinition() 的實現便可。日誌

下面的代碼有些長,咱們挑關鍵的部分分析便可:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
    // 惟一標識不能爲空
    Assert.hasText(beanName, "Bean name must not be empty");
    // 確保Bean定義不能爲空
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
    // 若是Bean定義是 AbstractBeanDefinition 類型, 那麼會進行一個驗證邏輯
    if (beanDefinition instanceof AbstractBeanDefinition) {
    	try {
            ((AbstractBeanDefinition) beanDefinition).validate();
    	}
    	catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex);
    	}
    }
    
    // 咱們的Bean定義是挨個被解析而後註冊到工廠中的
    // 這就意味着工廠中可能已經存在其餘Bean定義
    
    // 所以這裏會先嚐試從工廠中獲取一下咱們要註冊的bean定義
    // 確保工廠中是不存在這個bean定義的
    // 這裏存放 惟一標識+BeanDefinition 的容器beanDefinitionMap是 concurrentHashMap
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    // 若是已經存在相應的惟一標識了
    if (existingDefinition != null) {
        // 那麼爲判斷是否容許 BeanDefinition 的覆蓋
        // 若是不容許就拋出異常
    	// 通常都是不容許的
    	if (!isAllowBeanDefinitionOverriding()) {
    		throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    	}
    	// 若是容許覆蓋, 那麼會進行一個bean定義角色的判斷
    	// 若是已經存在的bean定義的角色小於當前要存放bean定義的角色, 那麼會進行一個日誌打印
    	// 通常在開發中也不多會進入這個邏輯
    	else if (existingDefinition.getRole() < beanDefinition.getRole()) {
    		// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    		if (logger.isInfoEnabled()) {
    			logger.info("Overriding user-defined bean definition for bean '" + beanName +
    					"' with a framework-generated bean definition: replacing [" +
    					existingDefinition + "] with [" + beanDefinition + "]");
    		}
    	}
    	// 若是兩者(已經存在的bean定義和要覆蓋的bean定義)不相同
    	// 那麼打印一個日誌
    	else if (!beanDefinition.equals(existingDefinition)) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Overriding bean definition for bean '" + beanName +
    					"' with a different definition: replacing [" + existingDefinition +
    					"] with [" + beanDefinition + "]");
    		}
    	} 
    	else { // 若是是其餘的極端狀況, 也會打印一個日誌
    		if (logger.isTraceEnabled()) {
    			logger.trace("Overriding bean definition for bean '" + beanName +
    					"' with an equivalent definition: replacing [" + existingDefinition +
    					"] with [" + beanDefinition + "]");
    		}
    	}
    	
    	// 進行一個bean定義的覆蓋,放置key-value到map中
    	this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else { // 若是 concurrentHashMap 中不存在相應的bean定義鍵值對
    	// 那麼會檢查這個工廠中bean的建立階段是否已經啓動
    	// 也就是這個工廠中的全部bean它是否被標記爲 created
    	// 若是已經啓動
    	if (hasBeanCreationStarted()) {
    		// Cannot modify startup-time collection elements anymore (for stable iteration)
    		// 那麼會進行一個同步
    		// 防止多個線程同時進行註冊的操做
    		synchronized (this.beanDefinitionMap) {
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    			List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    			updatedDefinitions.addAll(this.beanDefinitionNames);
    			updatedDefinitions.add(beanName);
    			this.beanDefinitionNames = updatedDefinitions;
    			removeManualSingletonName(beanName);
    		}
    	}
    	else { // 不然就會直接註冊, 不須要進行同步
    		// Still in startup registration phase
    		this.beanDefinitionMap.put(beanName, beanDefinition);
    		this.beanDefinitionNames.add(beanName);
    		removeManualSingletonName(beanName);
    	}
    	this.frozenBeanDefinitionNames = null;
    }
    
    if (existingDefinition != null || containsSingleton(beanName)) {
        // 重置 BeanDefinition 緩存的處理
    	resetBeanDefinition(beanName);
    }
}
複製代碼

當上面這個方法執行完畢後,工廠中的 BeanDefinitionMap 這個容器就已經存放了一個key-value鍵值對,key=惟一標識、value=beanDefinition。

當整個解析、註冊的事件處理完畢後,咱們返回到一開始給出的那個方法中:

/** * 經過解析器delegate去處理給定的bean element, 並解析出相應的bean Definition, 註冊到工廠中 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 經過delegate解析bean定義, 獲取到一個BeanDefinitionHolder實例
    // 這個實例, 其實就表明了xml文件中的一個完整的bean標籤對應的Bean Definition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    
    // 若是bdHolder不爲空, 說明解析成功了, 以後就是註冊環節了
    // 註冊環節咱們留着在下一篇中詳細展開
    if (bdHolder != null) {
    	bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    	try {
            // 註冊最終的BeanDefinition到工廠
            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));
    }
}
複製代碼

咱們看到最後執行的方法:getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

這裏採用了一個觀察者模式,當特定的事件觸發(成功完成Bean定義的解析、註冊),那麼會調用觀察者類(讀取器上下文)的方法,執行一些特定邏輯。

2、總結

那麼這裏,整個 Spring 對 Bean 的解析、裝配流程就分析完畢了。從宏觀上來看,beanDefinitionReader.loadBeanDefinitions() 這個邏輯就完成了。但要注意,截止到目前,咱們只是在工廠中註冊了Bean Definition,並無對其完成一個實例化的過程。 實例化的過程還要在後續的邏輯中才開始執行。

因而可知,Spring 對外提供的 API 接口僅僅是冰山一角,底層的實現就如同大海同樣深不可測。

那麼在下一章將帶來:defaultListableBeanFactory.getBean("student", Student.class); ,也就是依賴注入的詳細分析。

相關文章
相關標籤/搜索