Spring IOC容器源代码解析

 

  对于Spring的使用者而言,IOC容器实际上是什么呢?

  我们可以说:BeanFactory就是我们看到的IoC容器

  Spring为我们准备了许多种IoC容器,使我们可以从不同的层面,不同的资源位置,不同形式的定义信息来建立我们需要的IoC容器。 

  在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定: 

 

   

 

  BeanFactory接口只对IOC容器的最基本行为作了定义,根本不关心你的bean是怎样定义怎样加载的

  就像我们只关心从这个工厂里我们得到什么产品对象,至于工厂是怎么生产这些对象的,这个基本的接口并不关心这些。

  Spring提供了一个IOC容器(BeanFactory)基本的实现:XmlBeanFactory,这个实现使用xml来定义IOC容器中的bean

  我们常用的IOC实现有:

    XmlWebApplicationContext.java

    ClassPathXmlApplicationContext.java 

    FileSystemXmlApplicationContext.java    

 

   下面例子,简单的演示IOC容器的创建过程: 

    

 

  这些代码演示了以下几个步骤: 

  1. 创建IOC配置文件的抽象资源 
  2. 创建一个BeanFactory 
  3. 把读取配置信息的BeanDefinitionReader,这里是XmlBeanDefinitionReader配置给BeanFactory 
  4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入bean定义的过程。我们的IoC容器就建立起来了。

  

  在BeanFactory的源代码中我们可以看到: 

   

  BeanFactory 是一个接口,在实际应用中我们一般通过ApplicationContext来使用IOC容器。

  对开发者来说,可以认为BeanFactoryApplicationFactory在不同的使用层面上代表了Spring提供的IOC容器服务。 

  下面我们看看通过ClassPathXmlApplicationContext是怎样建立起IOC容器的显而易见我们可以通过new来得到IoC容器: 

  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

   

   构造方法:

    

  

  refresh的模板在AbstractApplicationContext.java中定义:
    public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
        // 1. 输出spring ioc启动日志
        ..........


        //2. 获取bean工厂,如果bean工厂已存在,则销毁并重新创建
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory); 

        try {
          // Allows post-processing of the bean factory in context subclasses.
          postProcessBeanFactory(beanFactory); 

          // Invoke factory processors registered as beans in the context.
          invokeBeanFactoryPostProcessors(beanFactory);

          // Register bean processors that intercept bean creation.
          registerBeanPostProcessors(beanFactory);

          // Initialize message source for this context.
          initMessageSource();

          // Initialize event multicaster for this context.
          initApplicationEventMulticaster();

          // Initialize other special beans in specific context subclasses.
          onRefresh();
          // Check for listener beans and register them.
          registerListeners();
          // Instantiate all remaining (non-lazy-init) singletons.
          finishBeanFactoryInitialization(beanFactory);
          // Last step: publish corresponding event.
          finishRefresh();
      }catch (BeansException ex) {
        // Destroy already created singletons to avoid dangling resources.
        destroyBeans();
        // Reset 'active' flag.
        cancelRefresh(ex);
        // Propagate exception to caller.
        throw ex;
      }
    }
  }

  

  // 创建bean工厂.
  ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

  // 返回bean工厂
  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

  //重建bean工厂
  refreshBeanFactory();

  //获取bean工厂
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  return beanFactory;
}


  //重建bean工厂,并加载xml配置文件
  protected final void refreshBeanFactory() throws BeansException {

  //如果bean工厂存在,则销毁
  if (hasBeanFactory()) {
    destroyBeans();         // 销毁bean
    closeBeanFactory();       // beanFactory = null; 销毁bean工厂代码
  }
  try {
    // 创建bean工厂
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    .........
    // 加载xml配置文件
    loadBeanDefinitions(beanFactory);
  }
  catch (IOException ex) {
    .........
  }
}

 

在AbstractXmlApplicationContext中定义了对资源的读取过程,默认由XmlBeanDefinitionReader来读取: 

   

   

 

  我们看到先把定义文件解析为DOM对象,然后进行具体的注册过程:

   

  具体的在BeanDefinitionDocumentReader中完成对,下面是一个简要的注册过程来完成bean定义文件的解析和IOC容器中bean的初始化 

   

   

 

  我们看到在parseBeanDefinition中对具体bean元素的解析式交给BeanDefinitionParserDelegate来完成的,下面我们看看解析完的bean是怎样在IOC容器中注册的: 
  在BeanDefinitionReaderUtils调用的是: 

    

  我们看看XmlBeanFactory中的注册实现: 

   

   

  这样就完成了Bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。 

 

  从上面的代码来看,我们总结一下IOC容器初始化的基本步骤: 

  1. 初始化的入口在容器实现中的refresh()调用来完成 
  2. 对bean 定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:

  通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统, URL等方式来定为资源位置。

   

  如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析beanxml定义文件 实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示 

这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关的方法 他们都是为处理BeanDefinitin服务的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这由IOC实现 BeanDefinitionRegistry接口来实现。

注册过程就是在IOC容器内部维护的一个HashMap来保存得到的 BeanDefinition的过程。这个HashMapIoC容器持有bean信息的场所,以后对bean的操作都是围绕这个HashMap来实现的。 
  然后我们就可以通过BeanFactoryApplicationContext来享受到Spring IOC的服务了
在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IoC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。 Spring本身提供了对声明式载入web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架实现。具体可以参见以后的文章。 
  在使用Spring IOC容器的时候我们还需要区别两个概念: 
  Beanfactory Factory bean,其中BeanFactory指的是IOC容器的编程抽象,比如ApplicationContext, XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定但Spring为我们提供了丰富的选择。  而 FactoryBean只是一个可以在IOC容器中被管理的一个bean,是对各种处理过程和资源使用的抽象,Factory bean在需要时产生另一个对象,而不返回FactoryBean本省,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的 Factory bean都实现特殊的org.springframework.beans.factory.FactoryBean接口,当使用容器中factory bean的时候,该容器不会返回factory bean本身,而是返回其生成的对象。Spring包括了大部分的  通用资源和服务访问抽象的Factory bean的实现,其中包括: 
  对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING为我们建立好的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容器里配置好就能很方便的使用了。 
现在我们来看看在Spring的事件机制,Spring中有3个标准事件,ContextRefreshEvent, ContextCloseEvent,RequestHandledEvent他们通过ApplicationEvent接口,同样的如果需要自定义时间也只需要实现ApplicationEvent接口,参照ContextCloseEvent的实现可以定制自己的事件实现: 

 

posted on 2016-03-03 10:26  快跑的小鸡  阅读(1718)  评论(0)    收藏  举报

导航