本blog以FileSystemXmlApplicationContext为例来分析Spring的初始化过程,本节主要介绍资源定位.
1.FileSystemXmlApplicationContext的类继承层次如下图所示
2.类图如下所示(本类图只标示了与本节相关的类、属性和方法)
3.类简介
DefaultResourceLoader: 资源定位类,可以通过一个String类型的path获取一个Resource,从而指向一个具体的文件。
此类中最重要的方法是Resource getResource(String location),该方法间接调用getResourceByPath来获取Resource.
FileSystemXmlApplicationContext覆写了父类DefaultResourceLoader中的getResourceByPath方法。
AbstractApplicationContext:refresh方法是入口方法也是核心方法,定义了生成ApplicationContext的实现步骤,使用了典型的模板方法模式,一些子步骤交给子类来实现。
obtainFreshBeanFactory方法可以获取一个真正的底层beanFactory,其中的refreshBeanFactory()和getBeanFactory()都是抽象方法
AbstractRefreshableConfigApplication: 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的工厂,最终会调用的构造方法如下:
public FileSystemXmlApplicationContext(String configLocations[], boolean refresh, ApplicationContext parent)
throws BeansException
{
super(parent);
setConfigLocations(configLocations);
if(refresh)
refresh();
}
setConfigLocations:实际是调用从父类(AbstractRefreshableConfigApplicationContext)继承下来的方法,目的是把值保存在从父类(AbstractRefreshableConfigApplicationContext)继承下来的属性configLocations中。
refresh是核心方法,启动了资源定位、解析等一系统的后续过程。此refresh方法实际上调用从父类(AbstractApplicationContext)继承下来的refresh方法.
(二)refresh方法解析(AbstractApplicationContext)
public void refresh()
throws BeansException, IllegalStateException
{
synchronized(startupShutdownMonitor)
{
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try
{
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch(BeansException ex)
{
beanFactory.destroySingletons();
cancelRefresh(ex);
throw ex;
}
}
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory()
{
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if(logger.isInfoEnabled())
logger.info("Bean factory for application context [" + getId() + "]: " + ObjectUtils.identityToString(beanFactory));
if(logger.isDebugEnabled())
logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
return beanFactory;
}
refreshBeanFactory是核心方法,此方法的实现交由AbstractApplicationContext的子类AbstractRefreshableApplicationContext来实现。
(三)refreshBeanFactory方法解析(AbstractRefreshableApplicationContext)
protected final void refreshBeanFactory()
throws BeansException
{
if(hasBeanFactory())
{
destroyBeans();
closeBeanFactory();
}
try
{
DefaultListableBeanFactory beanFactory = createBeanFactory();
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized(beanFactoryMonitor)
{
this.beanFactory = beanFactory;
}
}
catch(IOException ex)
{
throw new ApplicationContextException("I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
}
}
这个方法中最重要的方法是createBeanFactory()方法,这个方法是真正的创建工厂的方法,创建后的工厂保存在beanFactory属性中。
protected DefaultListableBeanFactory createBeanFactory()
{
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
refreshBeanFactory方法的loadBeanDefinitions(beanFactory);方法启动了bean的注册过程.loadBeanDefinitions(DefaultListableBeanFactory defaultlistablebeanfactory)的实现交给子类AbstractXmlApplicationContext来完成.
(四)loadBeanDefinitions源码解析(AbstractXmlApplicationContext)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws IOException
{
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
在loadBeanDefinitions方法中,生成了XmlBeanDefinitionReader,实际上bean的解析工作交给了beanDefinitionReader来处理.
在loadBeanDefinitions(DefaultListableBeanFactory beanFactory)中调用了重载的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法,源码如下
(五)loadBeanDefinitions(XmlBeanDefinitionReader reader)源码解析(AbstractXmlApplicationContext)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException
{
Resource configResources[] = getConfigResources();
if(configResources != null)
reader.loadBeanDefinitions(configResources);
String configLocations[] = getConfigLocations();
if(configLocations != null)
reader.loadBeanDefinitions(configLocations);
}
在本方法中调用的getConfigLocations实际上调用的父类(AbstractRefreshableConfigApplicationContext)继承下来的方法,configLocations[]的值实际上是在(一)调用FileSystemXmlApplicationContext的构造方法时设置进去的( setConfigLocations(configLocations)).在这个方法中,我们可以看reader.loadBeanDefinitions(configLocations);启动了真正的解析动作.
(六)public int loadBeanDefinitions(String locations[])源码解析(AbstractBeanDefinitionReader)
(AbstractBeanDefinitionReader是XmlBeanDefinitionReader的父类)
public int loadBeanDefinitions(String location, Set actualResources)
throws BeanDefinitionStoreException
{
ResourceLoader resourceLoader = getResourceLoader();
if(resourceLoader == null)
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
int loadCount;
if(resourceLoader instanceof ResourcePatternResolver)
try
{
Resource resources[] = ((ResourcePatternResolver)resourceLoader).getResources(location);
loadCount = loadBeanDefinitions(resources);
if(actualResources != null)
{
for(int i = 0; i < resources.length; i++)
actualResources.add(resources[i]);
}
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);
}
Resource resource = resourceLoader.getResource(location);
loadCount = loadBeanDefinitions(resource);
if(actualResources != null)
actualResources.add(resource);
if(logger.isDebugEnabled())
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
return loadCount;
}
getResourceLoader()getResourceLoader()getResourceLoader()getResourceLoader()getResourceLoader()实际上获取的是new的工厂自身,因为在源码(四)中XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setResourceLoader(this);工厂本身也实现了DefaultResourceLoader.
Resource resource = resourceLoader.getResource(location);是获取转换后的资源,实际上间接调用了FileSystemXmlApplicationContext.getResourceByPath方法,这个方法会把一个String转化为一个Resource。
loadBeanDefinitions(resource)则结束了本节的讨论,转入了下一篇blog.