当前位置:   article > 正文

从 SpringApplication 认识 Spring 应用启动过程

spring applicationinitor

一、SpringApplication 是什么?

Spring 应用的启动类。

二、SpringApplication 执行了什么?

  • 创建 ApplicationContext 实例

    ApplicationContext 就是我们所说的容器实例。

  • 注册 CommandLinePropertySource

    CommandLinePropertySource 的作用是将命令行参数输出为 Spring 属性。

  • 刷新 ApplicationContext

    这一步骤包括诸多操作,并且会加载所有的单例 bean

  • 触发 CommandLineRunner bean

    CommandLineRunner 是一个接口,它只有一个 run() 方法。

    凡是实现了此接口的类,如果被加载进容器,就会执行其 run() 方法。

    容器中可以包含多个实现 CommandLineRunner 的 bean,执行顺序可以遵从 Ordered 接口或者 @Order 注解设置。

三、bean 加载源

SpringApplication 有诸多 bean 加载源:

  • AnnotatedBeanDefinitionReader

    顾名思义,注解 bean 定义读取。

  • XmlBeanDefinitionReader

    xml 配置资源读取。

  • ClassPathBeanDefinitionScanner

    classpath 路径扫描。

  • GroovyBeanDefinitionReader

    ... ...

四、SpringApplication 创建

  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  6. this.bootstrapRegistryInitializers = new ArrayList<>(
  7. getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  8. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  9. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  10. this.mainApplicationClass = deduceMainApplicationClass();
  11. }

1、resourceLoader

参数可以为 null,为 null 时,使用默认:

(this.resourceLoader != null) ? this.resourceLoader: new DefaultResourceLoader(null);

2、primarySources

主要的 bean 定义来源。

3、webApplicationType

web 应用类型判断:

  • NONE:应用不会以 web 应用运行,且不会启动内嵌 web 服务器。

  • SERVLET:基于 servlet web 应用,运行于内嵌 web 服务器。

  • REACTIVE:响应式 web 应用,运行于内嵌 web 服务器。

4、bootstrapRegistryInitializers

BootstrapRegistryInitializer:回调接口,用于 BootstrapRegistry 初始化。

BootstrapRegistry:对象注册器,作用期间为从应用启动,Environment 处理直到 ApplicationContext 完备。

5、setInitializers

ApplicationContextInitializer 列表设置。

ApplicationContextInitializer:回调接口,用于 Spring ConfigurableApplicationContext 初始化。

通常用于 web 应用 ApplicationContext 自定义初始化。如注册 property source、激活 profile 等。

6、setListeners

ApplicationListener 列表设置。

ApplicationListener:应用事件监听接口,基于标准的 EventListener 接口,观察者模式实现。

7、mainApplicationClass

main class

五、SpringApplication.run() 逻辑

  1. public ConfigurableApplicationContext run(String... args) {
  2. long startTime = System.nanoTime();
  3. DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  4. ConfigurableApplicationContext context = null;
  5. configureHeadlessProperty();
  6. SpringApplicationRunListeners listeners = getRunListeners(args);
  7. listeners.starting(bootstrapContext, this.mainApplicationClass);
  8. try {
  9. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  10. ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  11. configureIgnoreBeanInfo(environment);
  12. Banner printedBanner = printBanner(environment);
  13. context = createApplicationContext();
  14. context.setApplicationStartup(this.applicationStartup);
  15. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  16. refreshContext(context);
  17. afterRefresh(context, applicationArguments);
  18. Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
  19. if (this.logStartupInfo) {
  20. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
  21. }
  22. listeners.started(context, timeTakenToStartup);
  23. callRunners(context, applicationArguments);
  24. }
  25. catch (Throwable ex) {
  26. handleRunFailure(context, ex, listeners);
  27. throw new IllegalStateException(ex);
  28. }
  29. try {
  30. Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
  31. listeners.ready(context, timeTakenToReady);
  32. }
  33. catch (Throwable ex) {
  34. handleRunFailure(context, ex, null);
  35. throw new IllegalStateException(ex);
  36. }
  37. return context;
  38. }

创建,刷新 ApplicationContext 并运行 Spring 应用。

1、startTime

使用 System.nanoTime(),计算耗时间隔更精确。不可用于获取具体时刻。

2、创建启动上下文

DefaultBootstrapContext = createBootstrapContext();

BootstrapContext:启动上下文,生命周期同 BootstrapRegistry。

DefaultBootstrapContext 继承了 BootstrapContext、BootstrapRegistry。

用于 BootstrapRegistry 初始化。

3、ConfigurableApplicationContext

可配置的 ApplicationContext。

4、获取事件监听器

SpringApplicationRunListeners = getRunListeners()。

Spring 应用运行期间事件监听。

5、starting 事件

listeners.starting():starting step。

6、启动参数处理

ApplicationArguments:提供 SpringApplication 启动参数访问。

7、应用环境配置

ConfigurableEnvironment = prepareEnvironment()

  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  2. DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
  3. // Create and configure the environment
  4. ConfigurableEnvironment environment = getOrCreateEnvironment();
  5. configureEnvironment(environment, applicationArguments.getSourceArgs());
  6. ConfigurationPropertySources.attach(environment);
  7. listeners.environmentPrepared(bootstrapContext, environment);
  8. DefaultPropertiesPropertySource.moveToEnd(environment);
  9. Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
  10. "Environment prefix cannot be set via properties.");
  11. bindToSpringApplication(environment);
  12. if (!this.isCustomEnvironment) {
  13. EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
  14. environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
  15. }
  16. ConfigurationPropertySources.attach(environment);
  17. return environment;
  18. }
  • configureEnvironment() 模板方法,代理执行 configurePropertySources() 及 configureProfiles() 方法。

    configurePropertySources():PropertySource 配置,用于添加、移除或者调序 PropertySource 资源。CommandLinePropertySource 在这一步处理。

    configureProfiles():应用 profile 设置。

  • ConfigurationPropertySources.attach(environment)

    ConfigurationPropertySources:提供对 ConfigurationPropertySource 的访问。

    attach(environment):就是将这个功能提供给 environment。

  • listeners.environmentPrepared(bootstrapContext, environment)

    environment-prepared step。

  • DefaultPropertiesPropertySource.moveToEnd(environment)

    DefaultPropertiesPropertySource:是一个 MapPropertySource,包含 SpringApplication 可以使用的一些默认属性。为了使用方便,默认会置于尾序。

  • bindToSpringApplication(environment)

    将 environment 绑定到 SpringApplication。

    Binder:用于对象绑定的容器。

8、configureIgnoreBeanInfo()

9、打印 Banner

printBanner()。

10、创建 ApplicationContext

createApplicationContext()。

内部通过 ApplicationContextFactory 创建。

ApplicationContextFactory:策略接口,默认实现为 DefaultApplicationContextFactory。

11、ApplicationStartup 设置

为容器设置 ApplicationStartup,用于记录启动过程性能指标。

12、ApplicationContext 准备

prepareContext()

  1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
  2. ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  3. ApplicationArguments applicationArguments, Banner printedBanner) {
  4. context.setEnvironment(environment);
  5. postProcessApplicationContext(context);
  6. applyInitializers(context);
  7. listeners.contextPrepared(context);
  8. bootstrapContext.close(context);
  9. if (this.logStartupInfo) {
  10. logStartupInfo(context.getParent() == null);
  11. logStartupProfileInfo(context);
  12. }
  13. // Add boot specific singleton beans
  14. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  15. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  16. if (printedBanner != null) {
  17. beanFactory.registerSingleton("springBootBanner", printedBanner);
  18. }
  19. if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
  20. ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
  21. if (beanFactory instanceof DefaultListableBeanFactory) {
  22. ((DefaultListableBeanFactory) beanFactory)
  23. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  24. }
  25. }
  26. if (this.lazyInitialization) {
  27. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  28. }
  29. context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
  30. // Load the sources
  31. Set<Object> sources = getAllSources();
  32. Assert.notEmpty(sources, "Sources must not be empty");
  33. load(context, sources.toArray(new Object[0]));
  34. listeners.contextLoaded(context);
  35. }
  • 设置环境

  • postProcessApplicationContext() 前置处理

    beanNameGenerator 设置,用于 bean 名称生成。

    resourceLoader 设置,用于资源加载。

    addConversionService:ConversionService 类型转换 Service。

  • applyInitializers()

    ApplicationContextInitializer 应用

  • contextPrepared 事件

    【spring.boot.application.context-prepared】step

  • BootstrapContext 关闭

  • 注册 springApplicationArguments bean

  • 注册 springBootBanner bean

  • AbstractAutowireCapableBeanFactory

    设置是否允许 bean 之间的循环依赖,并自动处理,默认为 true。

    设置是否允许 bean 定义覆盖,默认为 true。

  • lazyInitialization 懒加载

    设置 LazyInitializationBeanFactoryPostProcessor post-processor。

  • PropertySource 重排序

    设置 PropertySourceOrderingBeanFactoryPostProcessor post-processor。

  • getAllSources() bean 定义源加载

  • load() bean 定义加载,BeanDefinitionLoader

    用于从底层资源加载 bean 定义信息,包括 xml、JavaConfig。

    是基于 AnnotatedBeanDefinitionReader、XmlBeanDefinitionReader、ClassPathBeanDefinitionScanner 的门面模式。

    beanNameGenerator、resourceLoader、environment 设置。

    资源加载:

    1. private void load(Object source) {
    2. Assert.notNull(source, "Source must not be null");
    3. if (source instanceof Class<?>) {
    4. load((Class<?>) source);
    5. return;
    6. }
    7. if (source instanceof Resource) {
    8. load((Resource) source);
    9. return;
    10. }
    11. if (source instanceof Package) {
    12. load((Package) source);
    13. return;
    14. }
    15. if (source instanceof CharSequence) {
    16. load((CharSequence) source);
    17. return;
    18. }
    19. throw new IllegalArgumentException("Invalid source type " + source.getClass());
    20. }
  • contextLoaded() contextLoaded 事件

    【spring.boot.application.context-loaded】step。

13、ApplicationContext 刷新

refreshContext()

注册 shutdownHook。

Runtime.getRuntime().addShutdownHook(new Thread(this, "SpringApplicationShutdownHook"));

刷新操作:加载或刷新

  1. AbstractApplicationContext::refresh()
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
  5. // Prepare this context for refreshing.
  6. prepareRefresh();
  7. // Tell the subclass to refresh the internal bean factory.
  8. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  9. // Prepare the bean factory for use in this context.
  10. prepareBeanFactory(beanFactory);
  11. try {
  12. // Allows post-processing of the bean factory in context subclasses.
  13. postProcessBeanFactory(beanFactory);
  14. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
  15. // Invoke factory processors registered as beans in the context.
  16. invokeBeanFactoryPostProcessors(beanFactory);
  17. // Register bean processors that intercept bean creation.
  18. registerBeanPostProcessors(beanFactory);
  19. beanPostProcess.end();
  20. // Initialize message source for this context.
  21. initMessageSource();
  22. // Initialize event multicaster for this context.
  23. initApplicationEventMulticaster();
  24. // Initialize other special beans in specific context subclasses.
  25. onRefresh();
  26. // Check for listener beans and register them.
  27. registerListeners();
  28. // Instantiate all remaining (non-lazy-init) singletons.
  29. finishBeanFactoryInitialization(beanFactory);
  30. // Last step: publish corresponding event.
  31. finishRefresh();
  32. }
  33. catch (BeansException ex) {
  34. if (logger.isWarnEnabled()) {
  35. logger.warn("Exception encountered during context initialization - " +
  36. "cancelling refresh attempt: " + ex);
  37. }
  38. // Destroy already created singletons to avoid dangling resources.
  39. destroyBeans();
  40. // Reset 'active' flag.
  41. cancelRefresh(ex);
  42. // Propagate exception to caller.
  43. throw ex;
  44. }
  45. finally {
  46. // Reset common introspection caches in Spring's core, since we
  47. // might not ever need metadata for singleton beans anymore...
  48. resetCommonCaches();
  49. contextRefresh.end();
  50. }
  51. }
  52. }

作为启动方法,如果失败,则必须销毁所有已创建的单例bean。

  • StartupStep【spring.context.refresh】

  • 准备刷新 prepareRefresh()

    设置启动日期。

    设置 active 标志。

    initPropertySources():子类实现 PropertySource 初始化。

    validateRequiredProperties():校验 ConfigurablePropertyResolver#setRequiredProperties 设置的必需属性。

    obtainFreshBeanFactory():通过子类获取最新的内部 bean factory。如果存在旧的则先销毁,然后再创建新的返回。

  • prepareBeanFactory() 准备 bean factory

    setBeanClassLoader():默认为线程上下文类加载器,用于 bean 定义加载。

    setBeanExpressionResolver() spel 表达式解析设置:StandardBeanExpressionResolver。

    addPropertyEditorRegistrar():ResourceEditorRegistrar 用于 bean 创建过程。

    添加 ApplicationContextAwareProcessor post-processor。

    注册依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

    添加 ApplicationListenerDetector post-processor:用于检测发现实现了 ApplicationListener 的 bean。

    LoadTimeWeaver 处理。

    environment、systemProperties、systemEnvironment、applicationStartup 注册。

  • postProcessBeanFactory():用于子类实现,修改内部 bean factory。

    这一时期,所有的 bean 定义都已被加载,但还未实例化。

  • StartupStep【spring.context.beans.post-process】

  • invokeBeanFactoryPostProcessors() 触发所有已注册的 BeanFactoryPostProcessor

  • registerBeanPostProcessors() 注册 bean post-processor

  • StartupStep【spring.context.beans.post-process】 结束

  • initMessageSource() MessageSource 初始化

    容器内 bean 名称:messageSource。

    存在则检查并设置 ParentMessageSource。

    不存在则创建默认 DelegatingMessageSource,设置 ParentMessageSource 并注册。

  • initApplicationEventMulticaster() 事件分发初始化

    容器 bean:applicationEventMulticaster。ApplicationEventMulticaster 接口,用于管理 ApplicationListener,并执行事件分发。

    不存在则创建并注册 SimpleApplicationEventMulticaster 对象。

  • onRefresh()

    用于子类初始化一些特有的 bean。

    模板方法,用于重写实现刷新逻辑。

  • registerListeners() 监听器注册

    将实现了 ApplicationListener 接口的 bean 注册到容器。

  • finishBeanFactoryInitialization() 实例化所有余下的单例 bean。

    conversionService。

    注册内嵌值(${...})解析器。

    初始化 LoadTimeWeaverAware。

    停用类型匹配 ClassLoader。

    freezeConfiguration() 冻结所有的 bean 定义。所有注册的 bean 定义都不允许再有变更。

    preInstantiateSingletons() 实例化所有余下的单例 bean。

14、afterRefresh()

ApplicationContext 刷新完毕后调用。

15、StartupInfoLogger

记录应用启动信息。

16、started 事件

listeners.started()

17、Runner 调用

包括 ApplicationRunner 和 CommandLineRunner。

18 ready 事件

listeners.ready()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/609320
推荐阅读
相关标签
  

闽ICP备14008679号