spring的核心容器包括:core、beans、context、express language四个模块。所以对于一个简单的spring工程,最基本的就是依赖以下三个jar包即可:

    <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>

暂时先不考虑express language模块。

通过xml文件创建一个spring bean的大概过程:

  1. 主要考虑以下情况:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myTestBean" class="chapter02.MyTestBean"/> </beans>
    BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

    注:beanFactoryTest.xml指上述xml文件;chapter02.MyTestBean是一个简单的bean(包含一个私有属性,get,set方法)

  2. 关于new ClassPathResource("beanFactoryTest.xml")
    1. ClassPathResource类是Resource接口的一个实现类
    2. Resource接口继承了InputStreamSource接口
    3. InputStreamSource接口只有一个方法定义:InputStream getInputStream() throws IOException;
  3. 关于new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))
    1. 首先对传入的resource参数做封装
    2. 其次通过SAX读取XML文件的方式来准备InputSource对象
    3. 最后将准备好的数据通过参数传入真正的核心处理部分:doLoadBeanDefinitions
  4. 对于真正的核心处理部分:doLoadBeanDefinitions的处理过程,如下:
    1. 获取对XML文件的验证模式:DTD、XSD
    2. 加载XML文件,并得到对应的Document。通过SAX解析XML文档的步骤如下:
      1. 首先创建DocumentBuilderFactory
      2. 通过DocumentBuilderFactory创建DocumentBuilder
      3. 使用DocumentBuilder解析InputSource来返回Document对象
    3. 根据返回的Document注册Bean信息
  5. 对于根据返回的Document注册Bean信息的处理过程,如下:
    1. BeanDefinitionDocumentReader接口的实现类DefaultBeanDefinitionDocumentReader会获取到document对象的root节点
    2. 通过root节点获取所有的bean节点:一种是默认的bean节点:使用parseDefaultElement()方法进行处理;一种是自定义的bean节点:使用delegate.parseCustomElement()方法进行处理,其中delegate是根据自定义节点的命名空间获取到的自定义的节点处理器;以下只讨论对于第一种情况即:对于默认的bean节点的处理。
    3. 对于默认的bean节点有四种标签:import、alias、bean、beans,我们这里主要讨论最常用也最复杂的bean标签:
  6. 对于最常用也最复杂的默认节点中的bean标签的处理过程,如下:
    1. 首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement()方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder
      1. 提取元素中的id以及name属性
      2. 进一步解析其他所有属性以及子元素,并统一封装至GenericBeanDefinition类型的实例中;注:BeanDefinition存在三个实现类:RootBeanDefinition(父节点)、ChildBeanDefinition(子节点)、GenericBeanDefinition(Xml属性对应的java容器)
        1. 解析各种属性:scope属性、singleton属性、abstract属性、lazy-init属性、autowire属性、dependency-check属性、depends-on属性、autowire-candidate属性、primary属性、init-method属性、destory-method属性、factory-method属性、factory-bean属性
        2. 解析各种子元素:
          • 解析元数据:parseMetaElements
          • 解析lookup-method子元素:parseLookupOverrideSubElements
          • 解析replaced-method子元素:parseReplacedMethodSubElements
          • 解析构造函数参数:parseConstructorArgElements
          • 解析property子元素:parsePropertyElements
          • 解析qualifier子元素:parseQualifierElements
      3. 如果检测到bean没有指定beanName,那么使用默认规则为此bean生产beanName
      4. 将获取到的信息封装到BeanDefinitionHolder的实例中
    2. 当返回的bdHolder下存在自定义属性时,还需要对自定义标签进行解析。例如以下包含mybean:user自定义属性时:
      <bean id="test" class="test.Myclass">
      <mybean:user username="aaa"/>
      </bean>

      需要用到delegate.decorateBeanDefinitionIfRequired()进行自定义标签的处理,处理过程如下:

      • 遍历所有的属性以及所有的子元素
      • 根据节点获取标签的命名空间
      • 根据命名空间判断是否是默认标签。(这里只对非默认标签进行处理,因为对于默认标签在之前已经处理过了)
      • 根据命名空间找到对应的处理器
      • 使用相应的处理器进行修饰处理
    3. 对解析完成后的bdHolder进行注册:包括通过beanName的注册以及alias(别名)的注册
      1. 通过beanName注册BeanDefinition,关键方法:this.beanDefinitionMap.put(beanName, beanDefinition),主要步骤如下:

        • 对AbstractBeanDefinition的methodOvirrides属性进行校验
        • 如果beanName已经注册过:如果用户设置了不允许重复注册,则抛异常,否则直接覆盖,重新注册
        • 加入beanDfinitionMap
        • 清除解析之前留下的对应beanName的缓存
      2. 通过alias(别名)注册BeanDefinition,关键方法:this.aliasMap.put(alias, beanName),主要步骤如下:
        • alias与beanName相同,则不需要处理,并删除掉原有alias
        • 若alias存在,根据用户是否设置允许别名覆盖来进行相应的处理
        • alias循环检查。例如:当存在A(key)-->B(value)时,如果还存在B(key)-->A(value)或者B(key)-->C(value)、C(key)-->A(value)时,称为出现了循环。此时则会抛出异常
        • 注册alias:this.aliasMap.put(alias, beanName);
    4. 最后发出bean已注册完成的响应事件,通知相关的监听器  

spring bean的创建过程的更多相关文章

  1. Spring 源码(11)Spring Bean 的创建过程(2)

    Spring Bean 的创建过程介绍了FactoryBean 的创建方式,那么接下来介绍不是FactoryBean的创建方式,在创建过程中,又会分为单例的Bean的创建,原型类型的Bean的创建等. ...

  2. Spring 源码(12)Spring Bean 的创建过程(3)

    继续上一篇Spring Bean的创建过程的解读,上一篇介绍了Spring在创建过程中doGetBean方法,在执行过程中会调用getSingleton方法并且设置一个lambda表达式,这个lamb ...

  3. Spring 源码(13)Spring Bean 的创建过程(4)

    Spring Bean的创建过程非常的复杂,上一篇重点介绍了Spring在创建Bean的过程中,使用InstantiationBeanPostProcessor进行提前创建Bean,我们可以通过CGL ...

  4. 0003 - 基于xml的Spring Bean 的创建过程

    一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...

  5. Spring 源码(9)Spring Bean的创建过程的前期准备

    回顾总结 到目前为止,Spring源码中AbstractApplicationContext#refresh方法的已经解读到第11个方法finishBeanFactoryInitialization, ...

  6. Spring 源码(10)Spring Bean 的创建过程(1)

    Spring Bean的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化,BeanDefinition元数据的冻结等操作,都是为了在创建Bean的过程中保证Bean的正确的创建 ...

  7. Spring 源码(17)Spring Bean的创建过程(8)Bean的初始化

    知识回顾 Bean的创建过程会经历getBean,doGetBean,createBean,doCreateBean,然后Bean的创建又会经历实例化,属性填充,初始化. 在实例化createInst ...

  8. Spring 源码(14)Spring Bean 的创建过程(6)对象的提前暴露

    知识回顾 解析完Bean信息的合并,可以知道Spring在实例化Bean之后,属性填充前,对Bean进行了Bean的合并操作,这里的操作主要做了对Bean对象标记了@Autowired.@Value. ...

  9. Spring 源码(16)Spring Bean的创建过程(7)属性填充

    知识回顾 上一篇介绍了Spring中三级缓存的singletonObjects.earlySingletonObjects.singletonFactories,Spring在处理循环依赖时在实例化后 ...

随机推荐

  1. Loadrunner检查点使用总结

    在使用Loadrunner进行性能测试中,有时需要对性能测试中的功能是否全部正确进行判断.这里就需要用到“检查点”,本文总结了常用三种协议下检查点的使用方法,希望阅读本文后的小伙伴们能够掌握其使用方法 ...

  2. C#导出.csv格式的excel表

    .cs文件直接贴代码: using System; using System.Collections.Generic; using System.Data; using System.IO; usin ...

  3. LINUX 笔记-文件属性相关命令

    chgrp:该命令用于改变文件所属用户组 chown:该命令用于改变文件的所有者 chmod:该命令用于改变文件的权限 -R:进行递归的持续更改,即连同子目录下的所有文件都会更改  

  4. [mysql使用(1)] 64位Linux下安装mysql-5.7.13-linux-glibc2.5-x86_64

    由于公司临时让将Oracle的数据移植到mysql上面,所以让我在公司服务器上面安装一下mysql.下面就是我的安装过程以及一些错误解决思路.其实对于不同版本安装大体都有差不多. 1. 从官网下载 m ...

  5. 【ASP.NET MVC 学习笔记】- 15 Unobtrusive Ajax

    本文参考:http://www.cnblogs.com/willick/p/3418517.html 1.Unobtrusive Ajax允许我们通过 MVC 的 Help mothod 来定义 Aj ...

  6. 使用Angularjs和Vue.js对比

    使用Angularjs和Vue.js对比 之前项目都是使用Angularjs,(注明此处主要讲Angularjs 1)在初步使用Vue.js后做一个简答的对比笔记. 首先从理论上简单说一下各自的特点, ...

  7. 阿里云ubuntu安装jdk8+mysql+tomcat

    Mysql安装 使用apt-get安装 apt-get install mysql-server apt-get install mysql-client apt-get install libmys ...

  8. VC++6.0在win8.1系统下运行失败的解决办法

    在win8.1系统下安装了VC++6,.0编译软件之后,发现打不开.出现下面的错误: 解决办法: 安装文件目录:Microsoft Visual Studio--common--MSDev98--Bi ...

  9. 如何让Vim成为我们的神器

    Vim 是 Linux 系统上的最著名的文本/代码编辑器,也是早年的 Vi 编辑器的加强版,而 gVim 则是其 Windows 版.它的最大特色是完全使用键盘命令进行编辑,脱离了鼠标操作虽然使得入门 ...

  10. EduSoho程序上线实录

    1.1 修改配置文件 [root@web01 nginx]# cat /application/nginx/conf/extra/edusoho.conf server { listen 80; se ...