Spring 深入——IoC 容器 02( 二 )

obtainFreshBeanFactory() 源码:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();// 省略...}refreshBeanFactory() 是一个抽象方法 , 有两个具体的实现类:

  • AbstractRefreshableApplicationContext
  • GenericApplicationContext
在这里我们的 FSXAC 继承了 AbstractRefreshableApplicationContext , 所以我们看在这个类中 refreshBeanFactory() 的实现:
protected final void refreshBeanFactory() throws BeansException {//...try {DefaultListableBeanFactory beanFactory = this.createBeanFactory(); // 1beanFactory.setSerializationId(this.getId());this.customizeBeanFactory(beanFactory);this.loadBeanDefinitions(beanFactory);// 2///...}}我们抽出这两行代码进行分析:
  1. 创建 BeanFactory , 以 DefaultListableBeanFactory 作为 IoC 容器 。
  2. BD 的载入相关启动 。
我们到目前位置并没有看到与之相关的 Resource 定位信息 , 只看到 BD 的载入启动 , 所以针对 loadBeanDefinitions() 进行进一步分析 。该方法调用的是本类的一个抽象方法loadBeanDefinitions(DefaultListableBeanFactory var1) , 此方法是模板方法 , 由子类具体实现:
Spring 深入——IoC 容器 02

文章插图
而 FSXAC 就是 AbstractXmlApplicationContext 的子类 , 所以进而分析这个类的具体实现 。
Spring 深入——IoC 容器 02

文章插图
可以看到:
  1. 创建了 XmlBeanDefinitionReader 类 , 用于将 XML 文件中的 Bean 读取出来并加载 。
  2. 调用 XBDR 的 loadBeanDefinitions , 开始启动 BeanDefinition 的加载 。
  3. 在具体的实现中 , 分别传入不同的参数 , 但是在此方法中走判断时 , 调用了 this.getConfigResources() 这个方法在此类中是返回的 Resource[]是 null , 所以走第二个判断 , 获取以字符串数组 , 因为之前在 FSXAC 中就设置好了 。
    Spring 深入——IoC 容器 02

    文章插图
String[] 传入调用的是 XmlBeanDefinitionReader 的基类 AbstractBeanDefinitionReader 的方法:
Spring 深入——IoC 容器 02

文章插图
这里就是将 String 数组中的字符串 , 一个一个传入调用本类重载方法 , 并且对其进行计数 。
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return this.loadBeanDefinitions(location, (Set)null);}public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {// 取得 ResourceLoader , 使用的是 DeaultResourceLoaderResourceLoader resourceLoader = this.getResourceLoader(); // 关键代码1if (resourceLoader == null) {//...略} else {int loadCount;// 调用 DefaultResourceLoader 的 getResource 完成具体的 Resource 定位if (!(resourceLoader instanceof ResourcePatternResolver)) { // 关键代码2Resource resource = resourceLoader.getResource(location);loadCount = this.loadBeanDefinitions((Resource)resource);//... 略} else {// 调用 DefaultResourceLoader 的 getResources 完成具体的 Resource 定位try {Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);loadCount = this.loadBeanDefinitions(resources);//... 略}//... 略}}}可以看到最终调用的是两个参数的方法:(String location, Set<Resource> actualResources) , 通过上面代码的简要分析 , 我们提取出两个重要的信息:

经验总结扩展阅读