以下是基于基于 Xml 的 IOC 容器的初始化的加载,容器的定位请看上篇 基于Xml 的 IOC 容器的初始化(一)定位
3、开始启动
SpringIOC 容器对 Bean 配置资源的载入是从 refresh()函数开始的,refresh()是一个模板方法,规定了 IOC 容 器 的 启 动 流 程 , 有 些 逻 辑 要 交 给 其 子 类 去 实 现 。 它 对 Bean 配 置 资 源 进 行 载 入 ClassPathXmlApplicationContext 通过调用其父类 AbstractApplicationContext 的 refresh() 函数启 动整个 IOC 容器对 Bean 定义的载入过程,现在我们来详细看看 refresh() 中的逻辑处理:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1、调用容器准备刷新的方法,获取容器当前的时间,同时设置同步标识
prepareRefresh();
// 告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
//子类的refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3、为BeanFactory配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
//4、为工期的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
//5、调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
//6、为BeanFactory注册BeanPost时间处理器。
//BeanPostProcessor是Bean后置处理器,用于监听容器触发事件
registerBeanPostProcessors(beanFactory);
//7、初始化信息源,和国际化有关
initMessageSource();
//8、初始化容器事件传播器
initApplicationEventMulticaster();
//9、调用子类的某些特殊Bean初始化方法
onRefresh();
//10、为事件传播器注册事件监听器
registerListeners();
//11、初始化所有剩余的单例Bean
finishBeanFactoryInitialization(beanFactory);
//12、初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
//13、销毁已创建的Bean
destroyBeans();
//14、取消refresh操作,重置容器的同步标识
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();
}
}
}
}
refresh()方法主要为 IOC 容器 Bean 的生命周期管理提供条件,Spring IOC 容器载入 Bean 配置信息 从 其 子 类 容 器 的 refreshBeanFactory() 方 法 启 动 , 所 以 整 个 refresh() 中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这句以后代码的 都是注册容器的信息源和生命周期事件,我们前面说的载入就是从这句代码开始启动。
refresh() 方法的主要作用是:在创建 IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和 关闭,以保证在 refresh 之后使用的是新建立起来的 IOC 容器。它类似于对 IOC 容器的重启,在新建立 好的容器中对容器进行初始化,对 Bean 配置资源进行载入。
4、创建容器
obtainFreshBeanFactory()方法调用子类容器的 refreshBeanFactory()方法,启动容器载入 Bean 配置 信息的过程,代码如下:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
//这里只是定义了方法,并没有实现
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
}
AbstractApplicationContext 类中只抽象定义了 refreshBeanFactory()方法,容器真正调用的是 其子类 AbstractRefreshableApplicationContext 实现的 refreshBeanFactory()方法,方法的源 码如下:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果已经有容器,销毁容器中的bean,关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
//调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的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);
}
}
}
在这个方法中,先判断 BeanFactory 是否存在,如果存在则先销毁 beans 并关闭 beanFactory,接着 创建 DefaultListableBeanFactory,并调用 loadBeanDefinitions(beanFactory) 装载 bean 定义。
5、载入配置路径
AbstractRefreshableApplicationContext 类的中只是定义了抽象的 loadBeanDefinitions(beanFactory) 方法,实际是调用了 AbstractXmlApplicationContext 的
loadBeanDefinitions(beanFactory) 方法,,该方法的源码如下:
//注意看这里继承了AbstractRefreshableApplicationContext类
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
//实现父类抽象的载入Bean定义方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容 器使用该读取器读取Bean定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的
//祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
//为Bean读取器设置SAX xml解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
initBeanDefinitionReader(beanDefinitionReader);
//Bean读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
//Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取Bean定义资源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
//的Bean定义资源
reader.loadBeanDefinitions(configResources);
}
//如果子类中获取的Bean定义资源定位为空,
//则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
//是执行了这里的Bean资源的定义!
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的Bean定义资源
reader.loadBeanDefinitions(configLocations);
}
}
//这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法
//该方法在ClassPathXmlApplicationContext中进行实现,对于我们
//举例分析源码的FileSystemXmlApplicationContext没有使用该方法(返回null)
@Nullable
protected Resource[] getConfigResources() {
return null;
}
}
以 XmlBean 读取器的其中一种策略 XmlBeanDefinitionReader 为例。XmlBeanDefinitionReader 调 用其父类AbstractBeanDefinitionReader 的 reader.loadBeanDefinitions() 方法读取Bean配置资源。
由于我们使用 ClassPathXmlApplicationContext 作为例子分析,因此 getConfigResources 的返回值 为 null,因此程序执行 reader.loadBeanDefinitions(configLocations) 分支。
6、分配路径处理策略
在 XmlBeanDefinitionReader 的抽象父类 AbstractBeanDefinitionReader 中定义了载入过程。
AbstractBeanDefinitionReader 的 loadBeanDefinitions() 方法源码如下:
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
//重载方法,调用下面的loadBeanDefinitions(String, Set<Resource>);方法
//执行顺序2
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
//执行顺序3
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)
throws BeanDefinitionStoreException {
//获取在IoC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
//将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
//加载多个指定位置的Bean定义资源文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
//将指定位置的Bean定义资源文件解析为Spring IOC容器封装的资源
//加载单个指定位置的Bean定义资源文件
Resource resource = resourceLoader.getResource(location);
//委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
//重载方法,调用loadBeanDefinitions(String);
//第5点中 AbstractXmlApplicationContextd 类中的 reader.loadBeanDefinitions(configLocations);执行到这里
//执行顺序1
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
}
第四步的创建容器 AbstractRefreshableApplicationContext 的 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法实际上就是调用了 AbstractBeanDefinitionReader 的 loadBeanDefinitions() 方法。
从对 AbstractBeanDefinitionReader 的 loadBeanDefinitions() 方法源码分析可以该方法就做了两件事:
- 首先,调用资源加载器的获取资源方法 resourceLoader.getResource(location),获取到要加载的资源。
- 其次,真正执行加载功能是其子类 XmlBeanDefinitionReader 的 loadBeanDefinitions() 方法。。
在 AbstractBeanDefinitionReader 中的 loadBeanDefinitions()方法中调用了 AbstractApplicationContext 的 getResources() 方法(是因为AbstractApplicationContext 实现了 ResourceLoader ),跟进去之 后发现 getResources() 方法其实定义在 ResourcePatternResolver 中,此时,我们有必要来看一下 ResourcePatternResolver 的全类图:
从上面可以看到 ResourceLoader 与 ApplicationContext 的继承关系,可以看出调用 AbstractApplicationContext 的 getResources() 方法其实际调用的是 DefaultResourceLoader 中 的 getSource() 方 法 定 位 Resource , 因 为 ClassPathXmlApplicationContext 本身就是 DefaultResourceLoader 的实现类,所以此时又回到了 ClassPathXmlApplicationContext 中来。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68408.html