spring-IOC容器源码分析

6次阅读

共计 11722 个字符,预计需要花费 30 分钟才能阅读完成。

spring IOC 容器源码学习

我先介绍一下这篇文章的整体情况,首先我会介绍 IOC 容器的整体的框架逻辑,然后通过 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml"); 这段代码来一步步的分析 IOC 容器的调用流程。通过将 IOC 分为初始化,注入依赖两部分来进行分析

初始化


初始化的主要过程包括 xml 文件的读取,读取内容的解析,以及最终注册到 BeanFactory

先使用最基本启动 IOC 容器的例子

public class springTest1 {public static void main(String[] args){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
    }
}

maven 包的引用,spring-context 会自动将 spring-core、spring-beans、spring-aop、spring-expression 这几个基础 jar 包带进来。如果需要查看 spring 各个包对应哪些功能可以查看 spring 各模块之间的关系以及依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.12.RELEASE</version>
</dependency>

在接着下面的内容讲解之前,我们首先来看一下 spring IOC 容器各个接口类之间的继承关系

从上面的结构图我们可以看出来,ClassPathXmlApplicationContext经过了很多层接口的实现才到达 ApplicationContext。其中FileSystemXmlApplicationContextClassPathXmlApplicationContext功能基本相同。

AnnotationConfigApplicationContext 是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。

BeanFactory 简介

BeanFactory 是生产 bean 的工厂,负责生产和管理各个 bean 实例。其中的 ApplicationContext 其实就是一个 BeanFactory,不过 BeanFactory 是最基本的容器,而 ApplicationContext 是一个高级容器,实现了很多高级的功能

  1. ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,大家看源码会发现,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
  2. ApplicationContext 继承了 HierarchicalBeanFactoryHierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
  3. AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。
  4. ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。
准备

保存配置位置,并刷新

在调用 ClassPathXmlApplicationContext 的构造方法的时候,首先调用 setConfigLocations 方法,将配置文件的地址信息保存到 configLocations 数组中。之后会调用 refresh 方法进行刷新,该方法会将 applicationContext 销毁,重新执行一次初始化操作。

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {private Resource[] configResources;

  // 如果已经有 ApplicationContext 并需要配置成父子关系,那么调用这个构造方法
  public ClassPathXmlApplicationContext(ApplicationContext parent) {super(parent);
  }
  ...
  public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {super(parent);
    // 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
    setConfigLocations(configLocations);
    if (refresh) {refresh(); // 核心方法
    }
  }
    ...
}
@Override
public void refresh() throws BeansException, IllegalStateException {// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
   synchronized (this.startupShutdownMonitor) {

      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
      prepareRefresh();

      // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      // 这块待会会展开说
      prepareBeanFactory(beanFactory);

      try {
         //【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
         // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
         registerBeanPostProcessors(beanFactory);

         // 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了
         initMessageSource();

         // 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
         initApplicationEventMulticaster();

         // 从方法名就可以知道,典型的模板方法(钩子方法),// 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)onRefresh();

         // 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
         registerListeners();

         // 重点,重点,重点
         // 初始化所有的 singleton beans
         //(lazy-init 的除外)finishBeanFactoryInitialization(beanFactory);

         // 最后,广播事件,ApplicationContext 初始化完成
         finishRefresh();}

      catch (BeansException ex) {if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization -" +
                  "cancelling refresh attempt:" + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // 把异常往外抛
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();}
   }
}

创建载入 BeanFactory,通过执行refresh 方法中的 prepareRefresh 方法中的 refreshBeanFactory 方法,创建载入方法由 AbstractRefreshableApplicationContext.java 类实现

//AbstractRefreshableApplicationContext.java

@Override
protected final void refreshBeanFactory() throws BeansException {
   // 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
   // 注意,应用中 BeanFactory 本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前
   // ApplicationContext 是否有 BeanFactory
   if (hasBeanFactory()) {destroyBeans();
      closeBeanFactory();}
   try {
      // 初始化一个 DefaultListableBeanFactory,为什么用这个,我们马上说。DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 用于 BeanFactory 的序列化,我想不部分人应该都用不到
      beanFactory.setSerializationId(getId());

      // 下面这两个方法很重要,别跟丢了,具体细节之后说
      // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
      customizeBeanFactory(beanFactory);

      // 加载 Bean 到 BeanFactory 中
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}
   }
   catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
   }
}

创建 XMLBeanDefinitionReader

这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中
XMLBeanDefinitionReader 用来加载配置和解析

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
     throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // ... ...
    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

读取

创建处理每一个 resource

public int loadBeanDefinitions(String location, Set<Resource> actualResources)
     throws BeanDefinitionStoreException {
    // ... ...
    // 通过 Location 来读取 Resource
    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
    int loadCount = loadBeanDefinitions(resources);
    // ... ...
}
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {Assert.notNull(resources, "Resource array must not be null");
    int counter = 0;
    for (Resource resource : resources) {
        // 载入每一个 resource
        counter += loadBeanDefinitions(resource);
    }
    return counter;
}

处理 XML 每个元素 : 该功能不做详解,大概就是通过解析 xml 节点来获取 bean 的各个参数
解析和注册 bean

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 解析
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 注册
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name'" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

本步骤需要将 xml 的内容解析成 BeanDefinition, 然后存入BeanDefinitionHolder 中,然后利用 BeanDefinitionHolderBeanDefinition实例 put 到 BeanFactory 中。

注册

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);
        }
    }
}
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    // ......
    // 将 beanDefinition 注册
    this.beanDefinitionMap.put(beanName, beanDefinition);
    // ......
}

注册过程中,最核心的一句就是:this.beanDefinitionMap.put(beanName, beanDefinition),也就是说注册的实质就是以 beanNamekey,以 beanDefinitionvalue,将其 putHashMap中。

当完成初始化 IOC 容器后,如果 bean 没有设置 lazy-init(延迟加载) 属性,那么 bean 的实例就会在初始化 IOC 完成之后,及时地进行初始化。初始化时会先建立实例,然后根据配置利用反射对实例进行进一步操作,具体流程如下所示:

在创建 bean 和注入 bean 的属性时,都是在 doCreateBean 函数中进行的,我们重点看下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      // 说明不是 FactoryBean,这里实例化 Bean,这里非常关键,细节之后再说
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // 这个就是 Bean 里面的 我们定义的类 的实例,很多地方我直接描述成 "bean 实例"
   final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
   // 类型
   Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
   mbd.resolvedTargetType = beanType;

   // 建议跳过吧,涉及接口:MergedBeanDefinitionPostProcessor
   synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {
         try {
            // MergedBeanDefinitionPostProcessor,这个我真不展开说了,直接跳过吧,很少用的
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   // 下面这块代码是为了解决循环依赖的问题,以后有时间,我再对循环依赖这个问题进行解析吧
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean'" + beanName +
               "'to allow for resolving potential circular references");
      }
      addSingletonFactory(beanName, new ObjectFactory<Object>() {
         @Override
         public Object getObject() throws BeansException {return getEarlyBeanReference(beanName, mbd, bean);
         }
      });
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      // 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
      populateBean(beanName, mbd, instanceWrapper);
      if (exposedObject != null) {
         // 还记得 init-method 吗?还有 InitializingBean 接口?还有 BeanPostProcessor 接口?// 这里就是处理 bean 初始化完成后的各种回调
         exposedObject = initializeBean(beanName, exposedObject, mbd);
      }
   }
   catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;
      }
      else {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
   }

   if (earlySingletonExposure) {
      // 
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) {
               throw new BeanCurrentlyInCreationException(beanName,
                     "Bean with name'" + beanName + "'has been injected into other beans [" +
                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                     "] in its raw version as part of a circular reference, but has eventually been" +
                     "wrapped. This means that said other beans do not use the final version of the" +
                     "bean. This is often the result of over-eager type matching - consider using" +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

   // Register bean as disposable.
   try {registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

先看看 createBeanInstance 方法,此方法的目的就是实例化我们指定的类
populateBean(...) 方法,该方法负责进行属性设值,处理依赖。
initializeBean 属性注入完成后,这一步其实就是处理各种回调了

参考:

Spring 技术内幕(第 2 版)
Spring IOC 核心源码学习
Spring IOC 容器源码分析

正文完
 0