/**
* 重点在于构造方法理解
* @param configLocation
* @throws BeansException
*/
// configLocation 包含了 BeanDefinition 所在的文件路径
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
// 可以定义多个 BeanDefinition 所在的文件路径
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
// 在定义多个 BeanDefinition 所在的文件路径 的同时,还能指定自己的双亲 IoC 容器
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}
/**
* 如果应用直接使用 FileSystemXmlApplicationContext 进行实例化,则都会进到这个构造方法中来
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 动态地确定用哪个加载器去加载我们的配置文件
super(parent);
// 告诉读取器 配置文件放在哪里,该方法继承于爷类 AbstractRefreshableConfigApplicationContext
setConfigLocations(configLocations);
if (refresh) {
// 容器初始化
refresh();
}
}
/**
* 实例化一个 FileSystemResource 并返回,以便后续对资源的 IO 操作
* 本方法是在其父类 DefaultResourceLoader 的 getResource 方法中被调用的,
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
/**
* 容器初始化的过程:BeanDefinition 的 Resource 定位、BeanDefinition 的载入、BeanDefinition 的注册。
* BeanDefinition 的载入和 bean 的依赖注入是两个独立的过程,依赖注入一般发生在 应用第一次通过
* getBean() 方法从容器获取 bean 时。
*
* 另外需要注意的是,IoC 容器有一个预实例化的配置(即,将 AbstractBeanDefinition 中的 lazyInit 属性
* 设为 true),使用户可以对容器的初始化过程做一个微小的调控,lazyInit 设为 false 的 bean
* 将在容器初始化时进行依赖注入,而不会等到 getBean() 方法调用时才进行
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新,获取容器的当前时间,同时给容器设置同步标识
prepareRefresh();
// 告诉子类启动 refreshBeanFactory() 方法,BeanDefinition 资源文件的载入从子类的 refreshBeanFactory() 方法启动开始
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
// 为容器的某些子类指定特殊的 BeanPost 事件处理器
postProcessBeanFactory(beanFactory);
// 调用所有注册的 BeanFactoryPostProcessor 的 Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 为 BeanFactory 注册 BeanPost 事件处理器.
// BeanPostProcessor 是 Bean 后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
// 初始化信息源,和国际化相关.
initMessageSource();
// 初始化容器事件传播器
initApplicationEventMulticaster();
// 调用子类的某些特殊 Bean 初始化方法
onRefresh();
// 为事件传播器注册事件监听器.
registerListeners();
// 初始化 Bean,并对 lazy-init 属性进行处理
finishBeanFactoryInitialization(beanFactory);
// 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
// 销毁以创建的单态 Bean
destroyBeans();
// 取消 refresh 操作,重置容器的同步标识.
cancelRefresh(ex);
throw ex;
}
}
}
/**
* 在这里完成了容器的初始化,并赋值给自己私有的 beanFactory 属性,为下一步调用做准备
* 从父类 AbstractApplicationContext 继承的抽象方法,自己做了实现
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果已经建立了 IoC 容器,则销毁并关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建 IoC 容器,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 对 IoC 容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
// 载入 BeanDefinition,在当前类中只定义了抽象的 loadBeanDefinitions() 方法,具体实现 调用子类容器
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
// 给自己的属性赋值
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
/*
* 实现了基类 AbstractRefreshableApplicationContext 的抽象方法
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// DefaultListableBeanFactory 实现了 BeanDefinitionRegistry 接口,在初始化 XmlBeanDefinitionReader 时
// 将 BeanDefinition 注册器注入该 BeanDefinition 读取器
// 创建用于从 Xml 中读取 BeanDefinition 的读取器,并通过回调设置到 IoC 容器中去,容器使用该读取器读取 BeanDefinition 资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 为 beanDefinition 读取器设置 资源加载器,由于本类的基类 AbstractApplicationContext
// 继承了 DefaultResourceLoader,因此,本容器自身也是一个资源加载器
beanDefinitionReader.setResourceLoader(this);
// 设置 SAX 解析器,SAX(simple API for XML)是另一种 XML 解析方法。相比于 DOM,SAX 速度更快,占用内存更小。
// 它逐行扫描文档,一边扫描一边解析。相比于先将整个 XML 文件扫描近内存,再进行解析的 DOM,SAX 可以在解析文档的
// 任意时刻停止解析,但操作也比 DOM 复杂。
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化 beanDefinition 读取器,该方法同时启用了 Xml 的校验机制
initBeanDefinitionReader(beanDefinitionReader);
// Bean 读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}