探索SpringBoot-一塊兒看看Spring核心源碼之refresh(九)

前文回顧

以前講了探索SpringBoot-一塊兒看看Spring核心源碼之ApplicationContext(八),最後提到了ApplicationContextrefresh的三個核心過程分別是Bean發現、讀取、註冊。今天來進一步分析下源碼java

refresh之obtainFreshBeanFactory

咱們直接定位到AbstractApplicationrefresh函數中的下面這一行。有想要看以前的解析過程的看這篇探索SpringBoot-一塊兒看看Spring核心源碼之ApplicationContext(八)spring

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
複製代碼

看註釋能夠發現,這個方式是告訴子類去refresh內部bean factory,設計模式

咱們再進入到obtainFreshBeanFactory裏面。ide

/** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}
複製代碼

能夠看到,返回值beanFactory是由getBeanFacotry來獲取的。可是,以前進行過一個函數調用,refreshBeanFactory,這個又是幹什麼的呢?按照以前說法,refresh函數會先通過Bean的發現,讀取和註冊的過程,其實這個refreshBeanFactory就是進行Bean的發現,讀取和註冊實現。讓咱們繼續往下看。函數

/** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */
         //大意爲對這個context指定的bean factory執行特定的refresh操做。
         //若是以前有bean factory則銷燬,而後爲了下一個context的生命週期中初始化一個新的bean factory
	@Override
	protected final void refreshBeanFactory() throws BeansException {
                //判斷是否存在BeanFactory
		if (hasBeanFactory()) {
                        //銷燬Beans
			destroyBeans();
			closeBeanFactory();
		}
		try {
                        //建立一個BeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
                        //設置序列號,方便反序列化
			beanFactory.setSerializationId(getId());
                        //定製BeanFacotory
			customizeBeanFactory(beanFactory);
                        //發現BeanDefinition
			loadBeanDefinitions(beanFactory);
                        //將beanFactoryMonitor設置爲建立的beanFactory
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
複製代碼

一切都在註釋中了,先認真看一遍註釋。能夠發現,這裏最關鍵的Bean發現的過程是在loadBeanDefinitions中。嘗試查看實現,發現這個方法是一個抽象方法,具體實現類會根據不一樣的來源來實現不一樣的方式。咱們是XML的方式,直接看AbstractXmlApplicationContext便可。post

/** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */
     //大意爲用XmlBeanDefinitionReader來加載bean definitions
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		//用給定的BeanFactory來建立一個XmlBeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		//用這個上下文的資源加載環境來配置bean definition reader
		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		//容許子類對Reader提供特定的初始化,而後執行實際的加載Bean definitions
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}
複製代碼

看註釋,而後繼續看loadBeanDefinitions(beanDefinitionReader)this

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	    //注意這裏調用了getConfigResources()方法
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
複製代碼

注意這裏調用了getConfigResources()方法,咱們在回頭看一下ClassPathApplicationContext裏面的實現。沒錯,這裏AbstractXmlApplicationContext其實最終調用的是ClassPathApplicationContext裏面的實現。這裏使用到了模板模式,有不懂模板設計模式的同窗,以後我會單獨再補習一下。spa

@Override
	protected Resource[] getConfigResources() {
		return this.configResources;
	}
複製代碼

至此,能夠認爲是refreshBean的發現過程。debug

明天再分析下,Bean的讀取和註冊。設計

關於寫做

之後這裏天天都會寫一篇文章,題材不限,內容不限,字數不限。儘可能把本身天天的思考都放入其中。

若是這篇文章給你帶來了幫助,能請你寫下是哪一個部分嗎?有效的反饋是對我最大的幫助。

我是shane。今天是2019年8月14日。百天寫做計劃的第二十一天,21/100。

相關文章
相關標籤/搜索