探索SpringBoot-一起看看Spring核心源码之refresh(九)

1,440 阅读3分钟

前文回顾

之前讲了探索SpringBoot-一起看看Spring核心源码之ApplicationContext(八),最后提到了ApplicationContextrefresh的三个核心过程分别是Bean发现、读取、注册。今天来进一步分析下源码

refresh之obtainFreshBeanFactory

我们直接定位到AbstractApplicationrefresh函数中的下面这一行。有想要看之前的解析过程的看这篇探索SpringBoot-一起看看Spring核心源码之ApplicationContext(八)

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

看注释可以发现,这个方式是告诉子类去refresh内部bean factory,

我们再进入到obtainFreshBeanFactory里面。

	/**
	 * 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即可。

	/**
	 * 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)

	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里面的实现。这里使用到了模板模式,有不懂模板设计模式的同学,之后我会单独再补习一下。

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

至此,可以认为是refreshBean的发现过程。

明天再分析下,Bean的读取和注册。

关于写作

以后这里每天都会写一篇文章,题材不限,内容不限,字数不限。尽量把自己每天的思考都放入其中。

如果这篇文章给你带来了帮助,能请你写下是哪个部分吗?有效的反馈是对我最大的帮助。

我是shane。今天是2019年8月14日。百天写作计划的第二十一天,21/100。