Spring源码解析十四

通过前面的学习,我们已经了解了spring的初级容器是如何初始化了,但是相比于陌生的XmlBeanFactory而言ApplicationContext显然大家更加的熟悉,在spring高级容器ApplicationContext中,包含了初级容器XmlBeanFactory中所有的东西 。ApplicationContext在初级容器的基础之上,扩展了非常多的高级特性,同时也给我们提供了非常多的功能扩展点,通过这些功能扩展点,我们可以将spring这个框架的功能改造的更加满足于我实际的业务场景。从这一篇开始我们就一起去探索spring的高级容器ApplicationContext是如何初始化的吧。

我们先来看下ApplicationContext简单实用:
在这里插入图片描述可以看到,同样是解析xml文件,如果我使用ApplicationContext来解析的话,也就是将之前的XmlBeanFactory替换成了ApplicationContext的实现类CalssPathXmlApplicationContext,执行的结果和XmlBeanFactory是一样的。ApplicationContext接口的实现类也是比较多的。我们使用ClassPathXmlApplicationContext作为ApplicationContext初始化源码分析的入口。

通过ClassPathXmlApplicationContext的名称,我们可以知道它是从classpath路径加载和解析applicationContext.xml的。
我们进去ClassPathXmlApplicationContext 方法看下:
在这里插入图片描述
可以看到,在classPathXmlApplicationContextd的构造方法中,首先会把xml文件名称封装成一个String类型的数组,然后带上参数refresh的值true和parent值null,继续调用ClassPathXmlApplicationContext另外的一个重载构造方法。
我们到这个ClassPathXmlApplicationContext的重载构造方法中看下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,首先用super方法调用父类的构造器,我们层层的跟到父类AbstractApplicationContext,发现这个里面有两个方法:
我们到this() 方法中看下:
在这里插入图片描述
这里应该是初始化一个成员变量resourcePatternResolver,那getResourcePatternResolver方法能获取到什么呢?我们继续进去看下:
在这里插入图片描述
可以看到,成员变量resourcePatternResolver 被初始化了PathMatchingResourcePatternResolver类型,根据名称我们可以推测PathMatchingResourcePatternResolver应该是匹配路径的一个资源解析器,应该是获取xml文件资源的一个组件。

我们在看这个setParent方法:
在这里插入图片描述
可以看到往setParent方法中传入了参数parent,我们知道这个parent参数传入的是个null值。

我们在回到ClassPathXmlApplicationContext构造方法的位置:
在这里插入图片描述
applicationContext.xml 文件封装为String数组作为参数传入,然后调用方法setConfigLocations。
我们到这个setConfigLocactions方法中看下:
在这里插入图片描述
可以看到,在setConfigLocations方法中,通过我们传入的参数locations,构建了一个新的string数组configLocations,用于存放解析后的xml文件路径。
那这个resolvePath会怎么解析呢?我么看一下:
在这里插入图片描述
我们到方法resolveRequiredPlaceholders中看下:
在这里插入图片描述
也就是,我们传入的xml路径参数path中,如果存在占位符 ${},那方法resolveRequiredPlaceholders就可以解析占位符。而且,如果xml的路径中有${}占位符,但是却没有对应的默认属性值是会报错的。

到现在我们已经看到了,spring会为我们设置进去的xml路径进行一些准备处理,比如解析路径中的一些占位符,但是具体在什么时候加载和解析xml文件呢?
现在,我们再看ClassPathXMLApplicationContext构造方法:
在这里插入图片描述
前面我们已经看到,参数refresh的值为true,所以会调用refresh方法,那refresh方法到底是在干什呢?
我们到这个refresh方法中看下:

@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.
			// 初始化初级容器BeanFactory,并解析xml文件
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 对spring容器beanFactory做一些准备工作
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 空实现,留个子类去拓展实现。用于注册特殊的后置处理器来加载特殊的一些bean
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 执行BeanFactory即Spring容器级别的后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 在spring容器中,注册bean的后置处理器
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 在spring容器,初始化消息源MessageSource
				initMessageSource();

				// Initialize event multicaster for this context.
				// spring容器,初始化事件广播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 空实现,留给子类去拓展实现
				// 用于在实例化bean之前,做一些其他初始化bean的工作
				onRefresh();
			
				// Check for listener beans and register them.
				// 初始化spring容器中的各种监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 预先实例化那些非延迟加载的单例bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 初始化生命周期处理器,相应的事件通知
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					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;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

可以看到。容器ApplicationContext初始化的核心逻辑都在refresh中,下面的篇符中,我都是围绕则refresh方法来展开的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值