今天是2021年7月31日,2021年7月份的最后一天。我决定从今天起和大家一起学习springframework源码,由于工作日比较忙,所以,只能周末更新文章,望大家能够理解。
第一次自己写有关源码学习的文章,有什么不妥的地方希望大家提出宝贵意见,我会在后续文章中进行调整。
好了,废话不多说我们先从 ClassPathXmlApplicationContext 学起。
ClassPathXmlApplicationContext 是 ApplicationContext 的一个基类。通过读取类路径下的 xml bean 定义文件进行 bean 工厂创建并管理 bean 对象。
熟悉的程序
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean name="user" class="spring.beans.User"></bean>
</beans>
ClassPathXmlApplicationContext构造函数
ClassPathXmlApplicationContext构造函数主要进行两件事
- 加载指定的配置文件
- 刷新上下文环境(即初始化bean工厂)
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
super(parent)完成的事
- 初始化 org.springframework.context.support.AbstractApplicationContext.AbstractApplicationContext()
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
- 设置 parent org.springframework.context.support.AbstractApplicationContext.setParent(ApplicationContext)
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
setConfigLocations(configLocations) 是将配置文件赋值给 this.configLocations org.springframework.context.support.AbstractRefreshableConfigApplicationContext.setConfigLocations(String…)
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
refresh() 加载和刷新 bean 配置并将其加载到系统中org.springframework.context.support.AbstractApplicationContext.refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// org.springframework.context.support.AbstractApplicationContext.prepareRefresh()
// 刷新 context 上下文前的准备:
// 1、设置启动时间
// 2、设置 context 状态
// 3、初始化系统配置
// 4、验证系统配置是否完整
// 5、注册 ApplicationListeners
// 6、初始化 ApplicationEvents 集合
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory()
// 刷新 bean 工厂并将其实例返回
// 如果 bean 工厂已创建则现将其关闭,再初始化一个新的 bean 工厂实例
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// org.springframework.context.support.AbstractApplicationContext.prepareBeanFactory(ConfigurableListableBeanFactory)
// 配置 bean 工厂实例
// 1、设置 bean 工厂类加载器
// 2、设置 bean 创建后的处理类
// *3、注册特殊依赖项*
// 4、注册 environment bean
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// org.springframework.context.support.AbstractApplicationContext.postProcessBeanFactory(ConfigurableListableBeanFactory)
// 设置 bean 工厂自定义扩展类,可以更改 bean 定义信息。默认为空实现
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)
// 调用 bean 工厂自定义扩展处理
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(ConfigurableListableBeanFactory)
// 注册 bean 实例自定义扩展
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// org.springframework.context.support.AbstractApplicationContext.initMessageSource()
// 初始化 MessageSource
initMessageSource();
// Initialize event multicaster for this context.
// org.springframework.context.support.AbstractApplicationContext.initApplicationEventMulticaster()
// 初始化 ApplicationEvent 管理器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// org.springframework.context.support.AbstractApplicationContext.onRefresh()
// 初始化特定的刷新处理
onRefresh();
// Check for listener beans and register them.
// org.springframework.context.support.AbstractApplicationContext.registerListeners()
// 注册listener
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
// 结束 bean 工厂初始化
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// org.springframework.context.support.AbstractApplicationContext.finishRefresh()
// 结束刷新操作
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();
}
}
}
以上内容是 new ClassPathXmlApplicationContext(“applicationContext.xml”) 所做的事情,由于时间问题,只是大概介绍了各个方法的作用,后面我会进行展开讲解,例如:XML 配置是如何被读取并转换成 bean 定义,bean工厂是如何初始化的等等一系列问题。