Spring源码深度解析(二)

Spring源码深度解析(二)

一. 主要内容

  1. BeanFactory体系设计
  2. 核心接口
  3. BeanDefinition加载流程
  4. 设计思想总结

二. BeanFactory体系设计

BeanFactory是Spring中十分重要的接口,也是Spring IOC容器的顶级接口。它基于工厂模式,定义了最基本的IOC容器的功能,如获取Bean实例、查看Bean的类型和查看Bean是否存在等:
在这里插入图片描述

在BeanFactory的基础上扩展了很多接口,每个接口都有各自的功能。BeanFactory的继承体系如下:
在这里插入图片描述

三. 各种BeanFactory

  1. ListableBeanFactory:可以根据条件列出Bean的清单

    在这里插入图片描述

  2. AutowireCapableBeanFactory:提供了Bean自动注入的支持。

  3. HierarchicalBeanFactory:提供了容器继承的支持,可以维护一个parentBeanFactory父容器的引用,并通过它获取到父容器中的Bean。

    在这里插入图片描述

  4. ConfigurableBeanFactory:可对BeanFactory进行各种配置

  5. DefaultListableBeanFactory:BeanFactory的默认实现,实现了上述所有接口的功能,是BeanFactory的集大成者。

  6. XmlBeanFactory:DefaultListableBeanFactory的子类,继承了DefaultListableBeanFactory的所有功能,并在此基础上扩展了XML文件相关的定制化处理。

可以看出,Spring很好地贯彻了面向接口编程的原则,几乎所有的重要的类上面都定义了接口。而且,通过接口的继承,可以灵活地扩展出不同功能的接口。

四. 核心接口

  1. BeanDefinition:对一个Bean实例的描述,包括其类型、属性、构造器、依赖等。

    之前看过一个比喻:BeanFactory相当于一个汽车制造工厂,Bean对应于工厂中造出的各种车,而BeanDefinition就是每种车的图纸,描述了车的品牌、型号、所需零件、性能参数等。

  2. BeanDefinitionRegistry:BeanDefinition注册中心,定义了对 BeanDefinition 的各种增删改操作。

    在这里插入图片描述

  3. AliasRegistry:别名注册中心。Spring支持为一个Bean定义多个别名。

  4. SingletonBeanRegistry:单例Bean注册中心。Spring会缓存所有Singleton类型的Bean,每次获取到的都是同一个。

    BeanDefinition在定义了Bean的Scope,常用的有Singleton和Prototype,还可以扩展Scope接口进行自定义。

    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
  5. Resource:Spring对底层资源的封装,抽象了所有Spring内部可以使用到的底层资源,并提供了一些相关的查询和操作方法

    在这里插入图片描述

    对于不同来源的Resource,Spring都提供了对应的实现类,常用的有文件系统资源FileSystemResource和类路径资源ClassPathResource等。

五. BeanDefinition加载流程解析

BeanDefinition加载是Spring最重要的一个步骤,只有加载了所有定义的BeanDefinition后,才能根据其创建指定Bean,注入依赖,并完成后续一系列功能。BeanDefinition加载是在容器启动时自动完成的。

书中以XmlBeanFactory为例,讲解了BeanDefinition的加载和注册流程。虽然现在都以注解方式定义Bean,XML文件方式很少使用,但两种方式只是BeanDefinition的来源不同,核心处理流程是类似的,因此仍然以书中的内容为准。至于注解方式加载BeanDefinition的流程,如果感兴趣可以看下AnnotationConfigApplicationContext类。

XmlBeanFactory加载BeanDefinition的流程大致可以分为三个核心步骤:

  1. 资源的定位
  2. 将资源文件的解析为BeanDefinition集合
  3. 将解析好的BeanDefinition注入到容器中

六. 资源定位

可以显式指定BeanDefinition所在资源的位置,如书中代码所示:

Resource resource = new ClassPathResource("applicationContext.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);

这样显式Resource的方式省去了资源定位的步骤,但是,实际上没有这么用的,现在使用的都是ApplicationContext接口,其加载资源的处理在AbstractRefreshableApplicationContext#refreshBeanFactory()中,后面章节有具体叙述。

七. BeanDefinition解析

不管基于何种方式,现在拿到了BeanDefinition所在的资源文件Resource,则创建XmlBeanFactory,执行BeanDefinition解析的工作。

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
  super(parentBeanFactory);

  //加载配置文件
  this.reader.loadBeanDefinitions(resource);
}

XmlBeanFactory在维护了一个XmlBeanDefinitionReader实例,其功能就是从XML配置文件中解析出BeanDefinition。XmlBeanDefinitionReader是BeanDefinitionReader接口的实现类,BeanDefinitionReader接口的作用就是解析BeanDefinition。

解析过程中的核心类:

  1. XmlBeanFactory:XML形式的Bean工厂。
  2. XmlBeanDefinitionReader:负责从XML配置文件中读取BeanDefinition。
  3. DocumentLoader:专注于XML解析,将执行的XML文件解析成一个Document对象。
  4. BeanDefinitionDocumentReader:针对DocumentLoader解析好的Document,从中加载出BeanDefinition,并注册到容器中。
  5. BeanDefinitionParserDelegate:BeanDefinitionDocumentReader内部维护的委托对象,创建BeanDefinition实例并对其进行包装。
  6. BeanDefinitionReaderUtils:最终执行实际的BeanDefinition的注册。

XmlBeanFactory并没有自己完成BeanDefinition解析的工作,而是委托给各种不同的类去处理,每个类只关注一项具体的功能,这也是单一职责原则的很好的体现。

加载BeanDefinition流程:

在这里插入图片描述

八. BeanDefinition注册

九. 设计思想总结

  1. 工厂模式

  2. 面向接口编程

  3. 单一职责原则

  4. 策略模式:BeanDefinitionReader的作用是读取BeanDefinition。根据BeanDefinition的来源不同,Spring定义了不同的实现类(XmlBeanDefinitionReader、GroovyBeanDefinitionReader、PropertiesBeanDefinitionReader),并在相应的BeanFactory处指定了具体的实现类(XmlBeanFactory指定使用XmlBeanDefinitionReader)。

  5. 模板方法模式:参见DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions()方法:

    protected void doRegisterBeanDefinitions(Element root) {
      // Any nested <beans> elements will cause recursion in this method. In
      // order to propagate and preserve <beans> default-* attributes correctly,
      // keep track of the current (parent) delegate, which may be null. Create
      // the new (child) delegate with a reference to the parent for fallback purposes,
      // then ultimately reset this.delegate back to its original (parent) reference.
      // this behavior emulates a stack of delegates without actually necessitating one.
    
      //BeanDefinitionParserDelegate代理对象,主要用于BeanDefinition的解析与注册
      BeanDefinitionParserDelegate parent = this.delegate;
      this.delegate = createDelegate(getReaderContext(), root, parent);
    
      //profile属性处理,只解析满足当前profile的BeanDefinition
      if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
          String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
          // We cannot use Profiles.of(...) since profile expressions are not supported
          // in XML config. See SPR-12458 for details.
          if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isDebugEnabled()) {
              logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                           "] not matching: " + getReaderContext().getResource());
            }
            return;
          }
        }
      }
    
      //解析前置处理,模板方法,留给子类实现
      preProcessXml(root);
    
      //实际的BeanDefinition解析与注册
      parseBeanDefinitions(root, this.delegate);
    
      //解析前置处理,模板方法,留给子类实现
      postProcessXml(root);
    
      this.delegate = parent;
    }
    

    在父类方法中定义了方法的整体流程,并给出了核心实现parseBeanDefinitions()。在核心逻辑的前后,各定义了一个模板方法,交由子类进行定制化的处理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章