Spring Boot启动流程

Spring Boot启动

  1. 关键类、方法:ConfigurableApplicationContext SpringApplication#run。
    new SpringApplication(primarySources).run(args);

类方法说明

  1. SpringApplication类
    可以被用来从Java主方法中引导、启动一个Spring应用的类。默认,类会执行下面步骤来引导你的应用:
    1. 创建一个合适的ApplicationContext实例(依赖你的类路径)。
    2. 注册一个CommandLinePropertySource来暴露命令行参数为Spring属性。
    3. 刷新应用上下位,加载所有的单例bean。
    4. 触发任意的CommandLinerRunner bean。
      在多数情况下,静态run(Class, String[])可以直接从你的main方法调用,来引导你的应用。
      对于更高级的配置,SpringApplication实例可以在被运行前创建和自定义:
SpringApplication application = new SpringApplication(MyApplication.class);
//...在这里自定义应用设置
application.run(args);

SpringApplication可以从各种源中读取bean。通常建议@Configuration来引导你的应用,然而,你也可能从下面方式中设置getSources():
1. 由AnnotatedBeanDefinitionReader加载的全限定类名
2. 由XmlBeanDefinitionReader加载的XML资源位置,或者由GroovyBeanDefinitionReader加载的groovy脚本
3. ClassPathBeanDefinitionScanner扫描的包名
配置属性也被绑定到SpringApplication。这让动态设置SpringApplication属性成为可能,像额外的源("spring.main.sources",一个CSV列表)标志来表示web环境("spring.main.web-application-type=none")或者关闭横幅的("spring.main.banner-mode=off")。

  1. 方法SpringApplication(ResourceLoader resourceLoader, Class... primarySources)
    创建一个新的SpringApplication实例。应用上下文会从指定主要源加载bean(看SpringApplication类级别文档。实例可以在调用run(String...)之前自定义)。
  2. 方法Collection getSpringFactoriesInstance(Class type, Class[] paramenterTypes, Object... args)
  3. ResourceLoader接口
    加载资源的策略接口(例如,类路径或者文件系统资源)。org.springframework.context.ApplicationContext被要求提供这个功能,延申扩展org.springframework.core.io.support.ResourcePatternResolver支持。
    DefaultResourceLoader是一个独立实现,在ApplicationContext外是可用的,也被ResourceEditor使用。
    Resource类型的bean属性和Resource数组可以从字符串中填充,当运行在ApplicationContext中时,使用特殊的上下文资源加载策略。
  4. Resource getResource(String location):为给定的资源位置返回一个Resource处理。该处理应该总是可以重复使用的资源描述符,允许多次Resource#getInputStream()调用。
    1. 必须支持全限定URL,例如,"file:C:/test.dat"
    2. 必须支持类路径伪限定URL,例如, "classpath:test.dat"
    3. 应该支持相对路径,例如, "WEB-INF/test.dat"。(这会被具体实现,一般由ApplicationContext实现提供)
      注意,一个Resource处理不表明一个存在的资源;你需要调用Resource#exists去检查存在性。
  5. 类WebApplicationType
    web应用可能类型的枚举:NONE、SERVLET、REACTIVE。NONE:该类型应用不应该运行为web应用,不应该启动内置web服务器;SERVLET: 该类型应用应该运行为基于servlet的web应用,应该启动内置servlet web服务器;REACTIVE:该类型应用应该运行为响应式web应用,应该启动内置响应式web服务器。
  6. 方法WebApplicationType deduceFromClassPath
    从类路径上推断Web应用类型,SERVLET的标志类```{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"}。默认返回SERVLET。
  7. 接口 ApplicationContextInitializer
    初始化Spring ConfigurableApplicationContext的回调接口,优于被ConfigurableApplicationConetxt#refresh()刷新。
    一般用在web应用上,就是要求应用上下文的一些编程方式的初始化。例如,根据ConfigurableApplicationContext#getEnvironment() 上下文的环境来注册属性元或者激活配置。查看ContextLoader和FrameworkServlet,支持声明一个contextInitializerClasses上下文参数和初始化参数。
    ApplicationContextInitializer处理器鼓励去检查是否Spring的org.springframework.core.Ordered 接口已经被实现,或者是否org.springframework.core.annotation.Order注解是否出现,来排序实例。
  8. 方法void initialize(C applicationContext):初始化给定的应用上下文
  9. 类SpringFactoriesLoader
    用在框架内部的普通目的工厂加载机制。
    SpringFactoriesLoader#loadFactories加载并且实例化#FACTORIES_RESOURCE_LOCATION文件中给定类型的工厂,它们可能出现在类路径中的多个JAR文件中。spring.factories文件必须用Properties格式,在这种格式种,建时全限定的接口或者抽象类名称,值时逗号分隔的实现类名列表。例如:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
# example.MyService时接口的名称,MyServiceImpl1和MyServiceImpl2是两个实现
  1. 方法List loadFactoryNames(Class factoryType, ClassLoader classLoader)
    加载#FACTORIES_RESOURCE_LOCATION中给定的工厂实现的全限定类名,使用给定的类加载器。
  2. 方法loadSpringFactories
    FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories",从该文件中,加载资源,解析属性,并且添加到缓存中。
  3. 方法createSpringFactoriesInstances
    利用反射,加载、实例化上一步工厂配置中指定的名称对应的类,并添加大链表中。
  4. instantiateFactory
    使用反射,创建工厂实现类的实例。
  5. 方法 setInitializers
    设置将会应用到Spring ApplicationContext的ApplicationCOntextInitializer
  6. 接口ApplicationListener
    函数式接口。由应用事件监听器实现的接口。基于标准的java.util.EventListener接口,用于观察者设计模式。
    在Spring 3.0时,一个ApplicationListener通常可以声明感兴趣的事件类型。当用Spring ApplicationContext注册时,事件会相应地被过滤,监听器只在匹配的事件对象被调用。
  7. onApplicationEvent
    处理一个应用事件
  8. EventListener
    所有事件监听器接口必须继承的标记接口
  9. ApplicationEvent
    被所有应用事件继承的类。抽象是因为直接发布通用事件是没有意义的。
  10. ApplicationEventMulticaster
    被可以管理许多ApplicationListener对象,并且可以发布事件给它们的对象实现的接口。
    org.springframework.context.ApplicationEventPublisher,一般一个Spring org.springframework.context.ApplicationContext,可以使用ApplicationEventMulticaster作为实际发布事件的委派。
  11. deduceMainApplicationClass
    根据执行点的StackTraceElement,栈帧来与"main"比较,判断主应用类。
  12. StopWatch
    简单的秒表,允许许多任务的时间点,暴露总共运行事件和每个命名任务的运行事件。隐藏Sys#nanoTime()的使用,提供应用代码的可读性,减少计算错误的可能性。注意,这个对象不是设计成线程安全的,并且不使用同步。这个类通常被用于验证概念性证明工作中和开发中的性能,而不是作为生产应用的部分。在Spring Framework 5.2中,运行时被跟踪,并且以毫秒报告。
  13. start()
    开启一个未命名的任务。如果未先调用这个方法,那么stop()或者时机方法的结果是未定义的。
  14. ConfigurableApplicationContext
    由大多数应用上下文(如果不是所有)实现的SPI接口。
    提供功能配置一个应用上下文,加上在org.springframework.context.ApplicationContext接口中的应用上下文客户端方法。配置和生命周期方法在这里封装,未了避免让它们对ApplicationContext客户端代码明显。出现的方法应该只在启动和关闭代码中使用。
  15. SpringBootExceptionReporter
    函数式接口。用来支持SpringApplication启动错的自定义报告。SpringBootExceptionReporter通过SpringFactoriesLoader加载,并且必须声明由一个单一ConfigurableApplicationContext参数的公共构造器。
  16. boolean reportException
    报告一个启动失败给用户
  17. SpringApplicationRunListeners
    一组SpringApplicationRunListener。
  18. SpringApplicationRunListener
    SpringApplication#run方法的监听器。SpringApplicationRunListener通过SpringFactoriesLoader加载,并且应该声明一个公共构造器,接收一个SpringApplication实例,和一个String[] 参数。一个新的SpringApplicationRunListener实例会为每次运行创建。
  19. 类ApplicationStartingEvent
    尽早发布的事件,只要SpringApplication已经被启动——在Environment或者ApplicationContext可用之前,但是在ApplicationListener已经被注册后。事件源是SpringAplication自身,但是小心在早期阶段使用它的内部状态过多,因为它可能在后面的生命周期中被修改。
  20. 接口ConfigurableEnvironment
    被多数Environment类型实现的接口。提供功能:设置激活、默认profile、操作底层属性源。允许客户端通过ConfigurablePropertyResolver超接口设置、验证要求的属性、自定义边界服务等等。
    操作属性源。属性元可以被移除、重排序或者替换;并且额外的属性元可以使用MutablePropertySources实例添加,就是从getPropertySources()返回的。下面的例子依据ConfigurableEnvironment的StandardEnvironment实现,但是通常对任何实现可用,即时默认属性元可能不同。
    例子:添加一个有更高搜索优先级的新属性源:
ConfigurableEnvironment environment =  new StandardEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
Map myMap = new HashMap<>();
myMap.put("xyz", "myValue");
propertySources.addFirst(new MapPropertySource("My_MAP",  myMap));

例子:移除默认系统属性源

MutablePropertySources propertySources = environment.getPropertySources();
propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);

例子:为了测试目的,模拟系统环境

MutablePropertySources propertySources = environment.getPropertySources();
MockPropertySource mockEnvVars  = new MockPropertySource().withProperty("xyz", "myValue");
propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);

当一个Environment被ApplicationContext使用时,有一点是比较重要的,就是PropertySource操作要在上下文的org.springframework.context.support.AbstractApplicationContext#refresh()方法调用之前执行。这确保所有属性源在容器引导过程中都可用,包括通过org.springframework.context.support.PropertySourcesPlaceholderConfigurer属性占位符使用。

  1. prepareEnvironment
    1. 创建Env
    2. 配置Env,就是属性、profile
    3. 向监听器发送env准备好的事件
    4. 绑定env到SpringApplication
    5. 返回env对象
  2. configureIgnoreBeanInfo(COnfigurableEnvironment environment)
  3. createApplicationContext
    根据应用类型,反射实例化上下文类:SERVLET-org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;REACTIVE-org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;default-org.springframework.context.annotation.AnnotationConfigApplicationContext
  4. prepareContext()
    1. 给上下文设置env
    2. 后置处理应用上下文。应用任何紧密相关的后置处理ApplicationContext,如果需要,子类可以应用额外的处理:配置bean名称生成器、设置资源加载器、添加便捷服务
    3. 应用任何ApplicationContextInitializer到上下文,在上下文被刷新前。
      1. 获取初始化器。返回要被应用到Spring ApplicationContext的ApplicationContextInitializer集合
    4. 给监听器发送上下文已准备好事件。就是ApplicationContext已经被创建、准备好,但是在源被加载前调用
    5. 获取上下文内部的bean工厂,主备手动注册各种bean
    6. 加载源的bean到应用上下文
    7. 给监听器发送上下文准备好的事件。在应用上下文已经被加载,但是在应用上下文被刷新前调用。
  5. refreshContext()
    刷新应用上下文。最后调用的是一个同步方法。一次只能有一个线程调用。刷新配置的持久化表示,可能是XML文件、属性文件或者关系型数据库
  6. refresh()
    1. prepareRefresh():为刷新准备这个上下文,设置它的启动日期和激活标志,包括执行属性源的初始化
      1. 设置启动日期
      2. 设置激活标志为true
      3. 初始化属性源。初始化在上下文环境中的任意占位符属性源。用实际实例替换存根属性源
      4. 验证所有被标记为要求的属性为可解析的:看ConfigurablePropertyResolver#setRequiredProperties
      5. 存储预刷新ApplicationListeners
      6. 允许所有早期ApplicationEvents集合,一旦广播可用就发布
    2. obtainFreshbeanFactory():告诉子类刷新内部bean工厂。其实就是执行真实的配置加载,返回bean工厂。
    3. prepareBeanFactory():准备bean工厂,在这个上下文中使用该bean工厂。就是配置该工厂的标准上下文特征,例如上下文的类加载器和后置处理器。
    4. postProcessBeanFactory():允许在上下文子类中bean工厂的后置处理。在bean工厂的标准初始化后,修改该应用上下文的内部bean工厂。所有bean定义会被已经加载,但是还没有bean已经被实例化。这允许在某种ApplicationContext实现中注册特殊的BeanPostProcessors等等。
    5. invokeBeanFactoryPostProcessors():调用在该上下文中注册为bean的工厂处理器。实例化并且调用所有注册的BeanFactoryPostProcessor bean。
    6. registerBeanPostProcessors():注册bean处理器,拦截bean创建
    7. initMessageSource():为这个上下文初始化消息源
    8. initApplicationEventMulticaster():为这个上下文初始化事件广播。初始化ApplicationEventMulticaster。如果在该上下文中没有定义,使用SimpleApplicationEventMulticaster。现在才注册???
    9. onRefresh():初始化其他在特定上下文子类中的具体bean
    10. registerListeners():检查监听器bean,并且注册它们
    11. finishBeanFactoryInitialization():初始化所有保留的(非延迟初始化)单例。完成这个上下文的bean工厂的初始化,实例化所有剩余单例bean。
    12. finishRefresh():发布相应的事件
    13. destroyBeans():销毁已经创建的单例,避免悬挂资源
    14. cancelRefresh():重置active标志
    15. resetCommonCaches():重置Spring内核中公共的内省缓存,因为我们可能不再需要单例bean的元数据。
  7. AbstractAplicationContext类还是很重要的
  8. afterRefresh()
    在上下文已经被刷新后调用
  9. stop()
    停止秒表
  10. stated()
    给监听器发送事件,就是上下文已经被刷新,并且应用已经启动,但是CommandLineRunner和ApplicationRunner还没有被调用
    36.接口 ApplicationRunner
    一个函数式ean包含在SpringApplication中时,它是否应该运行。多个ApplicationRunner bean可以被定义在相同的应用上下文中,并且可以用Ordered接口或者@Order排序。
  11. running()
    在run方法完成前,立刻调用,当应用上下文已经被刷新,并且所有的CommandLineRunner和ApplicationRunner已经被调用后。

你可能感兴趣的:(Spring Boot启动流程)