最近看了Spring的初始化过程,这节讲述资源文件的定位。以FileSystemXmlApplicationContext为例来分析Spring的初始化过程。
1、FileSystemXmlApplicationContext的类结构图如图所示:
DefaultResourceLoader: 资源定位类,可以通过一个String类型的path获取一个Resource,从而指向一个具体的文件。
此类中最重要的方法是Resource getResource(String location),该方法间接调用getResourceByPath来获取Resource.
FileSystemXmlApplicationContext覆写了父类DefaultResourceLoader中的getResourceByPath方法。
AbstractApplicationContext:refresh方法是入口方法也是核心方法,定义了生成ApplicationContext的实现步骤,使用了典型的模板方法模式,一些子步骤交给子类来实现。
obtainFreshBeanFactory方法可以获取一个真正的底层beanFactory,其中的refreshBeanFactory()和getBeanFactory()都是抽象方法
AbstractRefreshableApplicationContext: refreshBeanFactory是对父类AbstractApplicationContext中refreshBeanFactory的实现。
createBeanFactory()是真正的创建工厂的方法,在此方法中创建了一个DefaultListableBeanFactory类型的工厂。
此类的中的beanFactory属性保存了创建的工厂句柄。
AbstractRefreshableConfigApplicationContext:这个类的最主要的作用的保存配置文件的信息,主要存储在configLocations数组中。
此类提供了setConfigLocations和getConfigLocations方法。
AbstractXmlApplicationContext:最核心的方法是loadBeanDefinitions(DefaultListableBeanFactory beanFactory),此方法是对父类 AbstractRefreshableApplicationContext中方法的覆盖,此方法拉开了解析XML配置文件的序幕。
FileSystemXmlApplicationContext:最底层的构造方法 FileSystemXmlApplicationContext(String configLocations[], boolean refresh, ApplicationContext parent)
getResourceByPath方法是对DefaultResourceLoader中getResourceByPath的覆盖。
4、源码解析
(一)、构造一个FileSystemXmlApplicationContext的工厂,最终会调用的构造方法如下:
setConfigLocations:实际是调用从父类(AbstractRefreshableConfigApplicationContext)继承下来的方法,目的是把值保存在从父类(AbstractRefreshableConfigApplicationContext)继承下来的属性configLocations中。
refresh是核心方法,启动了资源定位、解析等一系统的后续过程。此refresh方法实际上调用从父类(AbstractApplicationContext)继承下来的refresh方法.
(二)、refresh方法解析(AbstractApplicationContext)
refreshBeanFactory是核心方法,此方法的实现交由AbstractApplicationContext的子类AbstractRefreshableApplicationContext来实现。
(三)refreshBeanFactory方法解析(AbstractRefreshableApplicationContext)
这个方法中最重要的方法是createBeanFactory()方法,这个方法是真正的创建工厂的方法,创建后的工厂保存在beanFactory属性中。
refreshBeanFactory方法的loadBeanDefinitions(beanFactory);方法启动了bean的注册过程.loadBeanDefinitions(DefaultListableBeanFactory defaultlistablebeanfactory)的实现交给子类AbstractXmlApplicationContext来完成.
(四)loadBeanDefinitions源码解析(AbstractXmlApplicationContext)
在loadBeanDefinitions方法中,生成了XmlBeanDefinitionReader,实际上bean的解析工作交给了beanDefinitionReader来处理.
在loadBeanDefinitions(DefaultListableBeanFactory beanFactory)中调用了重载的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法,loadBeanDefinitions(XmlBeanDefinitionReader reader)源码解析(AbstractXmlApplicationContext),源码如下
在本方法中调用的getConfigLocations实际上调用的父类(AbstractRefreshableConfigApplicationContext)继承下来的方法,configLocations[]的值实际上是在(一)调用FileSystemXmlApplicationContext的构造方法时设置进去的( setConfigLocations(configLocations)).在这个方法中,我们可以看reader.loadBeanDefinitions(configLocations);启动了真正的解析动作.
(五)、public int loadBeanDefinitions(String locations[])源码解析(AbstractBeanDefinitionReader)
(AbstractBeanDefinitionReader是XmlBeanDefinitionReader的父类)
getResourceLoader()getResourceLoader()getResourceLoader()getResourceLoader()getResourceLoader()实际上获取的是new的工厂自身,因为在源码(四)中XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setResourceLoader(this);工厂本身也实现了DefaultResourceLoader.
Resource resource = resourceLoader.getResource(location);是获取转换后的资源,实际上间接调用了FileSystemXmlApplicationContext.getResourceByPath方法,这个方法会把一个String转化为一个Resource。