zoukankan      html  css  js  c++  java
  • Spring IOC 源码简单分析 01

    ### 准备

    ## 目标

    了解 Spring IOC 的基础流程

    ## 相关资源

    Sample code:<https://github.com/gordonklg/study>,spring module
    源码版本:Spring framework 4.3.9

    ##测试代码

    gordon.study.spring.ioc.IOC01_DefaultListableBeanFactory.java
     
    ioc01.xml
    <beans ...>
         <bean id="message" class="gordon.study.spring.common.Message">
            <property name="body" value="Hello World!" />
        </bean>
    </beans>

    ### 分析

    ## 整体流程分析

    org.springframework.core.io.Resource 是 Spring 抽象出来的代表底层资源的接口,从这些资源可以获得输入流(InputStream)。代码第16行创建了一个 org.springframework.core.io.ClassPathResource 实例,表示是相对于类路径的文件资源。
     
    org.springframework.beans.factory.support.DefaultListableBeanFactory 是本次分析的核心。DefaultListableBeanFactory 实现了 org.springframework.beans.factory.BeanFactory 接口,BeanFactory 接口定义了访问 Spring bean 容器的方法,通过该接口,我们可以从容器中获取预先配置的 bean。BeanFactory 接口定义了以下方法:
     
    BeanFactory 接口中最重要的方法就是 getBean(String),通过 bean name 获得指定的实例。代码第20行就是通过 getBean 方法从 bean 容器中获得 Message 类的实例。
     
    为了能够从 BeanFactory 中获取 bean 实例,BeanFactory 的实现类首先应该能获得 bean 定义,例如本例中通过 xml 文件配置的 message bean,这就需要为 bean 定义设计一个数据模型,在 Spring 中,org.springframework.beans.factory.config.BeanDefinition 接口用来表示 bean 定义。
     
    所有的 bean 定义应该放到同一个地方以便管理,org.springframework.beans.factory.support.BeanDefinitionRegistry 相当于 BeanDefinition 的注册表,为 Spring IOC 提供对 BeanDefinition 的注册、获取操作。
     
    Spring IOC 框架设计时决定让 BeanFactory 的实现类同时承担 BeanDefinitionRegistry 的职能,所以 DefaultListableBeanFactory 实现了 BeanDefinitionRegistry 接口,同时包含一个 Map<String, BeanDefinition> beanDefinitionMap 属性作为 BeanDefinition 的注册表。
     
    有了存放 BeanDefinition 的注册表,我们还需要工具类从配置文件中读取出 bean 定义,第18行的 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 用来从 xml 格式的配置文件中读取出 bean 定义,并将 bean 定义注册到其构造函数指定的 BeanDefinitionRegistry 实例中(本例中为  DefaultListableBeanFactory 实例)。第19行调用 loadBeanDefinitions 方法从指定 Resource 中读取 bean 定义。
     

    ## BeanFactory.getBean 流程分析

    当程序执行到第20行准备从 bean 容器中获取实例时,可以发现 DefaultListableBeanFactory 中已经成功读取到 BeanDefinition 信息:
    List<String> beanDefinitionNames[message]
    Map<String, BeanDefinition> beanDefinitionMap{message=Generic bean: class [gordon.study.spring.common.Message]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [ioc/ioc01.xml]}
     
    第20行 getBean 在本例中的核心流程如下:
    1. 尝试从 singletonObjects 中获取名字为 message 的 bean 实例
      由于 bean 默认是 Singleton 类型,所以 DefaultListableBeanFactory 中包含属性 Map<String, Object> singletonObjects 用来缓存所有 Singleton 类型实例。只有当指定名字的 Singleton 实例尚未被创建时才会创建实例,否则直接返回已创建的实例。
    2. 将 bean 标记为已创建(或即将创建完成)状态。就是将 bean name 放到 Set<String> alreadyCreated 中。
    3. 根据 BeanDefinition 生成 RootBeanDefinition,RootBeanDefinition 可以看做是合并过的最终 bean 定义。在本例中,RootBeanDefinition 与 BeanDefinition 基本一致,除了将原来值为空的 scope 改为 singleton。- Root bean: class [gordon.study.spring.common.Message]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [ioc/ioc01.xml]
    4. 将 RootBeanDefinition 放到 Map<String, RootBeanDefinition> mergedBeanDefinitions 中。
    5. 流经一个很复杂的过程,根据 RootBeanDefinition 中的信息,通过反射创建出 bean 实例,并装配好属性,再将 bean 实例放入 Map<String, Object> singletonObjects 中。
     
  • 相关阅读:
    eclipsesvn
    js邮箱和正则表达式
    jsreplace
    JQuery与Json转换
    thinkPHP时间戳格式化
    JS绝对定位到右下角
    chrome快捷键
    js配置示例
    JQuery class选择器
    JS调试技巧
  • 原文地址:https://www.cnblogs.com/gordonkong/p/7358784.html
Copyright © 2011-2022 走看看