Spring探秘2:ApplicationContext启动流程

     ApplicationContext是Spring框架中最基础的接口之一,可以认为其实现类就是一个Spring的环境(容器),而一个简单的Spring应用的启动过程就是一个ApplicationContext的实现类的实例化过程,是研究Spring源码的很好的切入点。这里研究的实现类是AnnotationConfigApplicationContext,运行的代码为前文Spring探秘0:源码构建中的测试代码,启动类的代码如下:

public class DemoApp {
  public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        DemoComponent component = context.getBean(DemoComponent.class);
        component.foo();

    }
}

要区分的一个概念就是“容器”,本文中提到的容器都是指Spring框架的容器,即管理Service,Dao以及Component这些Bean的一个“环境”。与SpingMVC的容器不同,SpringMVC的容器是管理Controller的环境。与Tomcat这些Web容器就更不一样了。

相关的类与接口

继承结构

     AnnotationConfigApplicationContext这个类从类名就可以看出,它是一个通过注解来配置的Spring容器,实例化该容器时,可以传入一个配置类,上面代码中的AppConfig就是我自定义的一个配置类,其中唯一的配置项就是通过@ComponentScan注解配置了扫描的包。
    AnnotationConfigApplicationContext这个类的继承结构如下图(图中只包含了与启动容器关系较大的类和接口,实际的继承层次要复杂得多):

applicationcontext

从中可以看出

  1. ApplicationContext最终还是要实现BeanFactory,而这个父接口的含义可以参考前一篇文章。因此可以说ApplicationContextBeanFactory功能上的增强。
  2. AnnotationConfigApplicationContext的直接父类GenericApplicationContext其实还有其他的一些子类,如GenericXmlApplicationContext等,分别用于表示不同配置方式的容器。

启动容器时涉及到的类

     容器的启动过程就是一个ApplicationContext的实例化过程,本文研究的容器实现类为AnnotationConfigApplicationContext,启动的过程中会涉及到许多其他的类,包括容器中的实例对象的实例化,向容器中注册的一些初始的处理器等。这里通过类图的形式总结了部分类以及这些类之间的关系。

startclass

各类的简介

自顶向下地简单介绍相关的类:

  • BeanDefinition: 用于描述一个Bean实例的信息;根据Bean的来源不同有具体的实现类,如AnnotatedGenericBeanDefinitionRootBeanDefinitionScannedGenericBeanDefinition等。
  • AbstractApplicationContext: 是ApplicationContetxt接口的抽象实现类,该类没有指定容器的配置类型,只实现了容器的一些通用功能,这些功能增强了简单的BeanFactory。与简单的BeanFactory相比,ApplicationContext应该能够主动探测到容器内的一些特殊的bean。因此该类自动注册了一些BeanFactoryPostProcessorBeanPostProcessorApplicationListener,在一些特殊的时期能够自动调用这些对象的功能。
  • BeanFactoryPostProcessor: 这就是一种ApplicationContext能够主动调用的特殊的Bean,从类名不难猜到,实现了该接口的Bean会在Bean工厂初始化完成后被调用(称为后置处理器)。因此我们可以通过实现该接口来插手Bean工厂初始化过程,从而扩展Spring的功能。值得注意的是,该接口的实现类只能去处理、修改bean definitions,而不应该对Bean实例作任何处理,因为调用时,bean都还没实例化。
  • BeanDefinitionRegistryPostProcessor,它是BeanFactoryPostProcessor的子接口,即除了实现BeanFactoryPostProcessor的功能之外,还能够实现动态地向容器中添加BeanDefinition的功能。该功能会在一般的BeanFactoryPostProcessor之前被调用。
  • PostProcessorRegistrationDelegateAbstractApplicationContext将调用后置处理器的功能委派给该类,应该只是为了减少每个类的代码量?
  • BeanDefinitionRegistry:registry意为“注册处”,所以这个接口也就是表示BeanDefinition注册的地方,一般都是由Bean工厂实现,用于管理BeanDefinition,包括注册、移除、获取等。对BeanDefinition有管理需要的地方就可以调用该接口的方法。
  • GenericApplicationContext: 是AbstractApplicationContext的子类,主要维护了一个DefaultListableBeanFactory实例,通过该实例实现了BeanFactory接口(装饰者模式)。另外也实现了BeanDefinitionRegistry接口,给有需要的类注册BeanDefinition
  • DefaultListableBeanFactory:这就是Spring内BeanFactory接口和BeanDefinitionRegistry的一个默认实现。
  • AnnotationConfigApplicationContext: 是GenericApplicationContext的子类,是一个独立的应用上下文(容器),构造时可以接收多个组件类作为参数(一般是配置类)。
  • ClassPathBeanDefinitionScanner: 是AnnotationConfigApplicationContext中一个重要的工具,用于扫描classpath上所有的Bean,并将相应的BeanDefifnition注册到给定的BeanDefinitionRegistry中。(一般registry就是一个BeanFactory或者是ApplicationContext,即当前的Spring容器)
  • AnnotatedBeanDefinitionReader:是AnnotationConfigApplicationContext中另一个重要的工具,也是用于接收一个Bean类,转换为BeanDefifnition并将其注册到registry中,但是不同点在于它只用于读取显式注册的类,即与ClassPathBeanDefinitionScanner相比没有扫描classpath的功能。

启动流程原理分析

     AnnotationConfigApplicationContext的构造方法的调用层次如下图所示:

constructor

构造父类GenericApplicationContext

  • 再递归地构造父类AbstractApplicationContext,该父类中的BeanFactoryPostProcessor的list就是在此时实例化的
  • 实例化beanFactory属性为DefaultListableBeanFactory。

工厂模式:AbstractApplicationContext类定义了一个抽象方法getBeanFactory(),通过该方法实现了BeanFactory接口。该方法就是需要子类去实现的工厂方法,不同的子类可能有不同的BeanFactory实现。

实例化reader属性

  • 设置reader中的registry,conditionEvaluator属性

  • 调用 AnnotationConfigUtils.registerAnnotationConfigProcessors() 向容器注册一些后置处理器的BeanDefinition(并且其实现类均为RootBeanDefinition),包括:

    • ConfigurationClassPostProcessor:是一个BeanDefinitionRegistryPostProcessor实现类,用于处理配置类
    • AutowiredAnnotationBeanPostProcessor:用于处理自动注入的类
    • CommonAnnotationBeanPostProcessor:支持JSR-250的注解
    • PersistenceAnnotationBeanPostProcessor:支持JPA的注解
    • EventListenerMethodProcessor
    • DefaultEventListenerFactory
  • 此时,reader的实例化已经完成,程序运行到这里(指AnnotatedBeanDefinitionReader构造方法的最后一行)时,Bean工厂中应该已经存在一些BeanDefinition

bdmap1

实例化scanner属性

  • 该实例化过程比较简单,只是在scanner的扫描过滤器中添加了@Component这个注解。

注册构造方法的参数传入的组件类

  • 调用reader.register(),追踪调用,最终的逻辑是在doRegisterBean()方法实现的

刷新 refresh()

  • 刷新容器是容器启动的最重要的一个阶段,有很多的工作包括准备Bean工厂、调用BeanFactoryPostProcessors、注册BeanPostProcessors等等,需要另外进行详细的分析。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章