{ SpringBoot }

  • SpringBoot启动分析-BeanDefinition

    |

    BeanDefinition

    BeanDefinition 是一个描述 Bean 信息的接口,它描述和定义了一个创建 bean 的所有基本信息,其中就包括了以下属性

    1. parentName: 双亲 bean 的名称
    2. beanClassName: bean 的类名,但一定有,因为如果该 bean 是由工厂bean 产生的,那么这里的 beanClassName 为空
    3. scope: 作用域,如 singleton, prototype
    4. lazyInit: 是否为懒加载,如果被设置为 lazy = true,那么这个 bean 会在使用的时候才会被实例化
    5. factoryBeanName:生产这个 bean 的工厂名
    6. propertyValues: 属性值
    7. role: bean 的角色类型,包括了 APPLICATION, SUPPORT, INFRASTRUCTURE




    AbstractDefinition

    AbstractDefinition 实现了 BeanDefinition 接口,为子类 RootBeanDefiniton, ChildBeanDefinition, GenericBeanDefinition 提供了 BeanDefinition 公用逻辑的封装,主要封装有以下:

    1. 定义了公共的构造函数
    2. 为属性值定义了 getter/ setter 等方法,方便获取设置属性值
    3. 提供了 overrideFrom() 用于覆盖 当前bean 的定义 及 applyDefaults() 用于设置 bean 的默认属性值



    值得一提的是,AbstractBeanDefinition 同时实现了 BeanMetadataAttributeAccessor,即为 BeanDefinition 扩展了以下功能 source, attreibute 等功能:

  • SpringBoot 启动分析-refresh()

    |

    refresh()


    上一篇分析 SpringBoot 启动过程中的 构造过程及 run(),在构造的过程中,主要是根据应用程序的类型设置 WebApplicationType,同时根据 spring.factories的配置读取初始化容器的一些监听器 listeners 和初始化器 initializers

    而在 run()中,主要是对应用上下文 ApplicationContext 创建并进行初始化,设置 WebApplicationType对应的 environment,然后 refreshContext(context) ,最后加载 listeners start(),running 并加入 SpringRunners.

    refreshContext(context) 主要有下面几个工作:

    1. prepareRefresh()
    2. prepareBeanFactory()
    3. postProcessBeanFactory()
    4. invokeBeanFactoryPostProcessors()
    5. registerBeanPostProcessors()
    6. initMessageSource()
    7. initApplicationEventMulticaster()
    8. onRefresh()
    9. registerListeners()
    10. finishBeanFactoryInitialization()
    11. finishRefresh()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
      public void refresh() throws BeansException, IllegalStateException {
    // 获取监视器锁
    synchronized(this.startupShutdownMonitor) {

    // 刷新上下文前的准备,记录状态,验证必要属性
    this.prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

    // 配置标准的 beanFactory,设置 classloader, bean表达解析器,同时注册重要的bean组件
    this.prepareBeanFactory(beanFactory);

    try {
    // 模板方法,交由子类对 beanFactory 进行后置处理
    this.postProcessBeanFactory(beanFactory);

    // 调用 beanFactoryPostPorcessor
    this.invokeBeanFactoryPostProcessors(beanFactory);

    // 注册容器中的 beanPostProcessors
    this.registerBeanPostProcessors(beanFactory);

    // 初始化国际工具类 MessageSource
    this.initMessageSource();

    // 初始化并注册事件广播器 ApplicationEventMulticaster
    this.initApplicationEventMulticaster();

    // 模板方法,根据应用的具体类型交由子类具体处理,如果是web类型,通常是构建webServer
    this.onRefresh();

    // 注册容器中的监听器,包括spring.factories 和 自定义 bean listenr
    this.registerListeners();

    // 实例化所有的单例 bean (非 Lazy),beanPostProcessor 开始起作用
    this.finishBeanFactoryInitialization(beanFactory);

    // refresh() 后的额外工作,包括清除resource cahce,注册 LifeCycleProcessor及发布上下文已经刷新的事件 ContexntRefreshedEvent
    this.finishRefresh();
    } catch (BeansException var9) {

    // 如果刷新上下文的过程中,出现异常,那么销毁所有已经创建的 bean
    this.destroyBeans();

    // 重置 context 的刷新状态,即将 active = false
    this.cancelRefresh(var9);
    throw var9;
    } finally {
    // 无论失败与否,已经不再需要 bean metadata,重置 Spring 的内核缓存
    this.resetCommonCaches();
    }
    }
    }
  • SpringBoot启动过程-run()

    |

    SpringApplication.run()

    在上一篇中,我们分析了 SpringBoot 启动过程中的 @SpringBootApplocation ,其主要功能就是加载对应的 @ConfigurationAuto Configure 模块中的组件信息,并将组件内容加入到容器中。

    这篇将开始分析 SpringBoot 的启动过程,而启动过程中最核心的两个部分就是 SpringApplication 的启动过程SpringApplication 的 run 方法 ,下面为分析过程:

    SpringApplication 的构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ...
    // 设置启动的源Class,即启动的SpringBootLearningApplication.class对象,包含了对应的 classLoader
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));

    // 设置了 webApplication的类型,尚未配置web,所以当前为 NONE (Servlet, Reactive)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    // 借助 SpringFactoriesLoader 找到 /META-INF/spring.factories 下的所有配置 key 为 ApplicationContextInitializer
    (所有的应用初始化器),实例化并设置到 setInitializers 这个集合属性中
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

    // 和上面一样, 通过 SpringFactoriesLoader 找到所有配置 key 为 ApplicationListener (所有的应用程序监听器),
    实例化并设置到 setListeners 集合属性中
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

    // 找到 StackTrace (方法调用堆栈)中的 main 方法,即入口类的名字,并 Class.forName 得到类对象
    this.mainApplicationClass = this.deduceMainApplicationClass();
    }


    ApplicationEvent

    SpringBoot 中使用了很多 Event 去响应容器状态,而 ApplicationEvent 为多个组件 bean 提供了消息通信的支持,其中就包括了接下来在 run( ) 使用到的 SpringApplicationEvent ,它实现了全局的 base ApplicationEvent,并扩展为多个 Spring 启动中的事件 Event,如下:

    1. ApplicationContextInitializedEvent
    2. ApplicationEnvironmentPreparedEvent
    3. ApplicationPreparedEvent
    4. ApplicationStartedEvent
    5. ApplicationReadyEvent
    6. ApplicationFailedEvent
    7. ApplicationStartingEvent


    事件的传递过程如下:

    1. SpringApplicationRunListener 调用对应的操作如 ( starting, running, contextLoad… )
    2. SpringApplicationRunListener 内部针对不同的事件,遍历内部集合调用对应的方法,具体实现类为 EventPublishingRunListener 调用
    3. EventPublishingRunListener 将对应的操作 ( starting, environmentPrepared.. ) 封装成对应的事件并通过属性 initialMulticaster push 广播出去
    4. 最后广播出去的事件如 ( ApplicationStartingEvent ) 会被 SpringApplication 中的 listeners 属性监听处理


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // SpringApplication.class
    public ConfigurableApplicationContext run(String... args) {
    listeners.starting();
    }

    // SpringApplicationRunListeners
    public void starting() {
    Iterator var1 = this.listeners.iterator();

    while(var1.hasNext()) {
    SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
    listener.starting();
    }
    }

    // EventPublishingRunListeners.class
    public void starting() {
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
  • SpringBoot启动过程 - @SpringBootApplication

    |

    SpringBoot 的启动过程如下:

    1
    2
    3
    4
    5
    6
    7
    @SpringBootApplication
    public class SpringbootlLearningApplication {

    public static void main(String[] args) {
    SpringApplication.run(SpringbootlLearningApplication.class, args);
    }
    }

    SpringBoot 简化了大量的配置的信息,几行代码就将 Spring Boot 服务启动,具体观察一下,有两部分指的注意:

    1. @SpringBootApplication 注解去指定启动类
    2. SpringApplication.run(SpringbootLearingApplication.class, args) 启动 Spring 容器


    @SpringBootApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
    ), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
    ...
    }

    可以看到,这里 @SpringBootApplication 是一个组合注解,它包含了以下三个重要的注解:

    1. @SpringBootConfiguration
    2. @EnableAutoConfiguration
    3. @ComponentScan


    @SpringBootConfiguration

    1
    2
    3
    4
    5
    6
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    }

    可以看出,@SpringBootConfiguration 实际上就是一个配置注解,与 @Configuration 不同的是,一个应用程序中只能使用一个 @SpringBootConfiguration,而在我们启动 SpringBootApplication 的时候就已经开启配置,而 @Configuration 可以根据需要进行 JavaConfig 的方式进行多个实例配置


    @EnableAutoConfiguration

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
    }

    @EnableAutoConfiguration这个复合annotation 的主要作用是开启容器的自动配置功能,而具体由 @AutoConfigurationPackage 和 @Import({AutoConfigurationImportSelector.class}) 实现。