spring源码解读开篇-1.bean图纸加载

好多看源码的小伙伴,像是在玩一个没有主线指引的游戏,在诺大的地图上到处碰壁,时不时钻进死胡同,一次次消磨掉了耐心,失去了再玩下去的勇气;这次呢,我来做你的引导npc

我来说说我的看法

其实坚持不下去,真的不怪你。
首先:spring已经发展很多年了,你不是从第一行代码看起。
其次:先有了设计思想,才有代码实现。而反过来从代码去找思想,就是反人类的做法
再者:代码量繁多,你不需要看完所有的代码。只需要看懂关键部分,看懂关键部分之后,其余的细枝末节需要用的时候再去看(借助文档等等工具),你会很轻松的看懂他们

好了下面我们开始正题

首先最宏观来看spring就是一个容器,容器里面可以装很多个bean,每个bean之间有着互相有关系,可以互相引用。这个容器被称为ioc容器;
spring源码解读开篇-1.bean图纸加载_第1张图片
从宏观上它做了以下的这些事情;
spring源码解读开篇-1.bean图纸加载_第2张图片

约定:咱们这里就以ClassPathXmlApplicationContext这个ioc容器的实现来进行讲解,其余的触类旁通;而且细节不做深入研究,点到即止。具体细节读者知道思想后再去看源码也不会困难
知识点扫盲:
什么是beanDefinition
beanDefinition就是spring用来封装bean定义信息的一个模型。把原始的bean元数据读取出来解析后通过该模型进行管理,和使用。好处当然是统一了bean定义信息。站在核心容器的视角:隔离了多种bean定义方式的复杂解析逻辑(比如xml,注解,properties等等,你甚至可以自定义)。核心容器只管取统一的beanDefinition来使用即可;
今天就来看读取bean配置信息的内容:先上图
也就是下图中的1,2,3标号,如何从xml转换成beanDefinition
spring源码解读开篇-1.bean图纸加载_第3张图片

1.第一个环节读取bean信息路标

classPathXmlApplicationContent是通过创建一个XmlBeanDefinitionReader的读取器来对xml进行读取翻译成BeanDefinition的。
这里面几个定义你需要了解:
1.ClassPathXmlApplicationContent: 就是一个容器的实现
2.XmlBeanDefinitionReader: 用来读取解析xml中的bean配置的类
3.BeanDefinition: 存储bean定义信息一个包装类,提供bean的配置信息

!!!那么关键就是去找到这个XmlBeanDefinitionReader在哪里创建和使用的;

跟着路标来找代码,没有标路标的部分可以暂时不看:

路标1:构造器
构造ioc容器

//构造ioc容器
	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

路标2:另一个构造器
调用另一个参数较多的构造器

 	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
 	//调用另一个构造器来进行构造
		this(new String[] {configLocation}, true, null);
	}

路标3:refresh()
然后又通过找到refresh();刚启动肯定要强制刷新容器。买了新房子你还得装修呢不是?

	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
		//构造器的第一行先调用父级一个参数的构造函数
		super(parent);
		//把配置路径解析存到configLocations属性上
		setConfigLocations(configLocations);
		if (refresh) {
		//刷新容器这里是真正干活的地方;
			refresh();
		}
	}

路标4:obtainFreshBeanFactory
到这里方法开始变得复杂了,但是不要走错路,跟着路标走;这里面的东西你扫一眼就好了,主要看到obtainFreshBeanFactory()这个位置;这里面就是实例化一个具体容器,把配置加载出来的地方;(如果你懂装饰者模式的话可能会有些感触,不懂也没关系)

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//准备进行容器刷新
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//告诉具体的子类去刷新包含的bean factory,这里其实是用的包装者模式,包装者中包含一个引用,然后返回该beanFactory容器对象
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//为容器做一些准备,设置一些它需要的东西和配置等等
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//允许子类去实现一些后置处理逻辑
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//执行容器中注册的BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//注册BeanPostProcessor,在创建bean的前后等执行
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//国际化相关,感兴趣自行了解
				initMessageSource();

				// Initialize event multicaster for this context.
				//注册事件广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//子类重写这个方法,在容器刷新的时候可以自定义逻辑,默认什么都不做
				onRefresh();

				// Check for listener beans and register them.
				//检查监听器bean并且注册,监听的就是上面广播器发出的各种不同类型的消息
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//初始化所有剩下的非懒加载的单例bean!!!!!
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//最后一步:发布相应的事件,比如容器刷新完成事件
				finishRefresh();
			}

			catch (BeansException ex) {
				logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

路标5:refreshBeanFactory()

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {		//刷新beanFactory
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

路标6:loadBeanDefinitions()
是不是看见曙光了。这里就是加载我们配置的xml等等信息的地方

	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

路标7:找到对应的加载逻辑
类路径为

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)

我们可以看到ClassPathXmlApplicationContext就是这个类的子类;

这里主要逻辑就是构造一个bean定义信息读取器

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		//创建一个类型为XmlBeanDefinitionReader的解析器来读取xml的内容
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		//容器本身就是一个资源加载器的实现
		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.
		//初始化redaer
		initBeanDefinitionReader(beanDefinitionReader);
		//进行读取
		loadBeanDefinitions(beanDefinitionReader);
	}

路标8:进到loadBeanDefinitions()

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		//加载Redource类型的资源
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		//加载字符串路径类型的资源最终还是会转换成Resource类型
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

到这里点到即止,再往下如何解析xml等等部分的内容,最终解析出beanDefinitionr然后通过org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition方法把bean定义信息注册到BeanDefinitionRegistry中,
因为ClassPathXmlApplicationContext 本身就是一个BeanDefinitionRegistry的子类DefaultListableBeanFactory的一个装饰的装饰者,所以也可以说就是把定义信息注册到它自己中;
如何解析这部分内容不做深入,有兴趣自己看一下。

下面做一个总结:

第一步做的事情:
ClassPathXmlApplicationContext 通过创建XmlBeanDefinitionReader 去把xml中bean定义信息转换成BeanDefinition加载到它自己中;为后续创建bean准备好了图纸

ClassPathXmlApplicationContext 在这个过程中拥有两个能力:
1.是一个ResourceLoader,资源加载器,能读取xml资源
2.是一个BeanDefinitionRegistry,是一个注册管理器,能管理bean定义信息
为什么说它拥有这两个能力呢,
第一个其实是因为ClassPathXmlApplicationContext 是ResourceLoader的简介子类
第二个呢,线索在refreshBeanFactory();其实是一个装饰者模式的体现,ClassPathXmlApplicationContext 其实是DefaultListableBeanFactory实现的一个装饰;而DefaultListableBeanFactory又是一个BeanDefinitionRegistry的实现,所以ClassPathXmlApplicationContext 可以使用BeanDefinitionRegistry管理器的逻辑;
你可以自己试试从源码中找到这段代码来验证:

	protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

好了第一阶段bean信息加载到此结束了。bean的图纸画好了。但是这里的beanDefinition并不是真正的bean。只是一个bean定义信息而已;切记

你可能感兴趣的:(spring源码,spring,java,设计模式)