Spring boot启动过程及扩展点分析

20 篇文章 0 订阅

Springboot(以1.5.21版本为例)项目中,项目启动除了jvm的经典过程外,以下是Spring boot项目启动过程:

  1. org.springframework.boot.loader.JarLauncher中的main函数即为上一步jvm加载并执行的函数
  2. 编写有SpringApplication的应用主函数为其中的启动一个环节

接下来跟下Spring boot启动过程【org.springframework.boot.loader.JarLauncher】:

  1. registerUrlProtocolHandler,将SystemProperties的“java.protocol.handler.pkgs”设置为:“自定义路径”+|+“org.springframework.boot.loader”【ftp\http\jar...】
  2. createClassLoader,将BOOT-INF下的lib(三方jar包)和classes(项目已编译二进制文件)路径作为classLoader(LaunchedURLClassLoader)初始化路径,并初始化
  3. getMainClass,获取manifest下的startClass,即应用项目中的主函数
  4. 将currentThread中ContextClassloader设置为上一步的LaunchedURLClassLoader
  5. 创建MainMethodRunner,使用上述classloader进行mainClass的加载,并基于反射执行该mainClass的main函数

继续,进入我们的main函数,我们一般的处理如下:

@SpringBootApplication

@MapperScan({"com.xxx.framework.example.mapper.my"})

@EnableFeignClients(basePackages = {"com.xxx.framework.example"})

@EnableEurekaClient

public class ExampleApplication {

  public static void main(String[] args) {

    SpringApplication.run(com.xxx.framework.example.ExampleApplication.class, args);

  }

}

进入Spring boot初始化过程【org.springframework.boot.SpringApplication】:

  1. initialize(ExampleApplication.class)
    1. sources中加入ExampleApplication.class
    2. 判断是否存在"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"这两个类【prepareEnvironment步骤中创建和配置environment】
    3. setInitializers,加载所有类型为org.springframework.context.ApplicationContextInitializer的类,主要作用是作为初始化Spring的回调接口【prepareContext步骤中触发初始化
    4. setListeners,加载所有类型为org.springframework.context.ApplicationListener的类,主要是Application事件监听,用于启动后过程触发【prepareContext最后步骤中触发回调
  2. run
    1. 设置SystemProperties:java.awt.headless=“true”(即不需要显示设备、键盘或鼠标)
    2. 找到所有的org.springframework.boot.SpringApplicationRunListener,并进行初始发布(默认是发布org.springframework.boot.context.event.ApplicationStartedEvent的事件)
    3. prepareEnvironment,准备环境
      1. 创建org.springframework.core.env.ConfigurableEnvironment实例,并设置属性源和activeProfile设置(未真正获取这些属性源的值)
      2. 发布org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent的事件
    4. createApplicationContext,创建应用上下文
      1. 依据1.b判断结果选择实际的上下文类型(true:AnnotationConfigEmbeddedWebApplicationContext,false:AnnotationConfigApplicationContext)
    5. prepareContext,准备处理context上下文
      1. context.setEnvironment(environment)
      2. postProcessApplicationContext,context后置处理,
        1. 在BeanFactory中注册name为“org.springframework.context.annotation.internalConfigurationBeanNameGenerator”的单例beanNameGenerator
        2. 设置loader,若context类型为GenericApplicationContext->setResourceLoader,若context为DefaultResourceLoader→setClassLoader
      3. applyInitializers,触发1.c步骤中的所有初始化器【此处boot和cloud会有不同的使用,2.f.v步骤会进行触发】
      4. 发布空的事件
      5. 将1.a步骤中的source加入到一个BeanDefinitionLoader(boot),依据的仍是context的BeanDefinitionRegistry,主要是看这些source是否需要作为bean加入到Spring的context中去
      6. 发布org.springframework.boot.context.event.ApplicationPreparedEvent的事件
    6. refreshContext,刷新上下文【进入Spring的核心加载过程】
      1. prepareRefresh,准备刷新上下文
        1. initPropertySources,初始化属性源及env、SystemProperties等,即将所有的key-value均进行实例化
        2. validateRequiredProperties,校验必须存在的属性【暂时未找到在哪儿能配置】
      2. obtainFreshBeanFactory,获取新的beanFactory
        1. refreshBeanFactory,清除旧的beanFactory,生成新的beanFactory,并进行相应初始化操作【两个子类:org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory,org.springframework.context.support.GenericApplicationContext#refreshBeanFactory,待总结Context类图】
          1. customizeBeanFactory,设置是否允许beanDefinition被覆盖和是否允许循环引用
          2. loadBeanDefinitions,加载beanDefinition(bean的定义)到beanFactory中去【org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions,还有其他的,TODO】
            1. 创建AnnotatedBeanDefinitionReader(class或xml形式编写的bean,以下简称reader)和ClassPathBeanDefinitionScanner(package path方式,以下简称scanner)为该beanFactory进行beanDefinitions的注册
            2. reader扫描所有当前的已加入的class,scanner扫描所有的basePackages,均将其beanDefinitions进行注册
            3. 获取所有的resource的位置(XML bean definition文件),并先后用reader和scanner进行尝试找到beanDefinition
        2. 返回该beanFactory
      3. prepareBeanFactory,配置factory的标准上下文特征,比如context的类加载器和后置处理器
        1. 配置classloader
        2. 配置后置处理器-postProcessor(ApplicationContextAwareProcessor,ApplicationListenerDetector【若存在loadTimeWeaver的bean,LoadTimeWeaverAwareProcessor】)
        3. 设置忽略检查依赖的接口(EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware)
        4. 设置几个默认的bean(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext)
      4. postProcessBeanFactory,让实际的context类型进行后期的beanFactory处理
        1. 列出几个子类:
          1. org.springframework.web.context.support.AbstractRefreshableWebApplicationContext#postProcessBeanFactory
            1. 配置bean后置处理器-postProcessor(ServletContextAwareProcessor)
            2. 设置忽略检查依赖的接口(ServletContextAware,ServletConfigAware)
          2. org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#postProcessBeanFactory
            1. 调用:org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#postProcessBeanFactory
              1. 配置bean后置处理器-postProcessor(WebApplicationContextServletContextAwareProcessor)
              2. 设置忽略检查依赖的接口(ServletContextAware)
              3. registerWebApplicationScopes

            2. basePackages和annotatedClasses不为空,则进行scan和register
          3. org.springframework.web.context.support.GenericWebApplicationContext#postProcessBeanFactory
            1. 配置bean后置处理器-postProcessor(ServletContextAwareProcessor)
            2. 设置忽略检查依赖的接口(ServletContextAware)
            3. web场景针对性处理:WebApplicationContextUtils.registerWebApplicationScopes,WebApplicationContextUtils.registerEnvironmentBeans
          4. org.springframework.jca.context.ResourceAdapterApplicationContext#postProcessBeanFactory
            1. 配置bean后置处理器-postProcessor(BootstrapContextAwareProcessor)
            2. 设置忽略检查依赖的接口(BootstrapContextAware)
            3. 设置几个默认的bean(BootstrapContext,WorkManager)
          5. org.springframework.web.context.support.StaticWebApplicationContext#postProcessBeanFactory
            1. 配置bean后置处理器-postProcessor(ServletContextAwareProcessor)
            2. 设置忽略检查依赖的接口(ServletContextAware,ServletConfigAware)
            3. web场景针对性处理:WebApplicationContextUtils.registerWebApplicationScopes,WebApplicationContextUtils.registerEnvironmentBeans
      5. invokeBeanFactoryPostProcessors,调用context中注册为bean的beanFactory(注意不是上一步的bean)的postProcesser
        1.  首先,会找到预先设置的几个【问题来了,什么时候设置的:1.c设置,2.e.iii中部分ApplicationContextInitializer会增加,可能有以下几个:ConfigurationWarningsPostProcessor,CachingMetadataReaderFactoryPostProcessor,PropertySourceOrderingPostProcessor】
        2. 进入第一步判断
          1. 如果beanFactory instanceof BeanDefinitionRegistry【此过程会记录哪些已经处理过,第三步会用】
            1. 拆分为BeanFactoryPostProcessor(List<BeanFactoryPostProcessor> regularList)和BeanDefinitionRegistryPostProcessor(List<BeanDefinitionRegistryPostProcessor> registryList)
            2. 首先将预设的几个进行拆分
            3. 然后,主要处理类型为BeanDefinitionRegistryPostProcessor
              1. 找到的类型为BeanDefinitionRegistryPostProcessor,且继承了PriorityOrdered的postProcesser
              2. 找到的类型为BeanDefinitionRegistryPostProcessor,且继承了Ordered的postProcesser
              3. 找到的类型为BeanDefinitionRegistryPostProcessor,且不为上面两步的postProcesser
              4. 以上三步均做这样几个事
                1. 排序
                2. registryList加入这些新找到的postProcessor
                3. 触发这些新找到的postProcessor
            4. 最后,处理BeanFactoryPostProcessor,并全部触发
          2. 如果不是,仅触发这几个预设postProcessor即可
        3. 接下来,需要找到BeanFactoryPostProcessor类型的其他bean进行触发
          1. 跳过上一步已经处理过的
          2. 找到继承了PriorityOrdered的postProcesser
          3. 找到继承了Ordered的postProcesser
          4. 找到不为上面两步的postProcesser
          5. 以上三步均做这样几个事
            1. 排序
            2. 触发
      6. registerBeanPostProcessors,在factory中注册bean的生成拦截器:BeanPostProcessor(内含before和after)
        1. 根据类型BeanPostProcessor找到所有的postProcessor
        2. 找到继承了PriorityOrdered的postProcesser
        3. 找到继承了Ordered的postProcesser
        4. 找到不为上面两步的postProcesser
        5. 以上三步均做这样几个事
          1. 排序
          2. 将自己注册到beanFactory中(实际触发在真正的构造过程中)
      7. initMessageSource,初始化messgeSource
      8. initApplicationEventMulticaster,初始化事件广播器
      9. onRefresh,做一些特殊处理
        1. initThemeSource
        2. org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#onRefresh会进行内置容器的创建
      10. registerListeners,将ApplicationListener的监听器名字加到viii步中初始化好的多播器中,并将之前发布的event(前面几步有发布一些事件)使用此多播器进行广播
      11. finishBeanFactoryInitialization,构造所有非lazy的bean
        1. 初始化context的转换服务 (???):beanFactory.setConversionService(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)
        2. beanFactory中注册value 解析器(如PropertyPlaceholderConfigurer)
        3. 构造LoadTimeWeaverAware,尽早初始化LoadTimeWeaverAware bean,以便尽早注册它们的转换器
        4. 冻结bean definition,允许缓存所有的bean 定义的元数据,不期待进一步的更改
        5. preInstantiateSingletons,构造所有的bean
          1. 触发构造bean过程(有点绕,不过没有特别的过程,就是会触发beanPostProcessor)
          2. 触发类型为SmartInitializingSingleton的bean的后置处理【spring boot也有很多bean实现】
      12. finishRefresh,最后一步
        1. initLifecycleProcessor,初始化lifecycle处理器
        2. getLifecycleProcessor().onRefresh(),开启所有类型为org.springframework.context.Lifecycle的bean,执行其start方法
        3. 发布ContextRefreshedEvent的事件
        4. registerApplicationContext,如果系统属性中设置了“spring.liveBeansView.mbeanDomain”,那么将当前Application信息加入到context中去(没看懂还是,不过没什么特殊处理)
    7. afterRefresh,调用所有的ApplicationRunner和CommandLineRunner
    8. listeners.finished,SpringApplicationRunListener监听结束
      1. 目前仅一个该监听,发布ApplicationReadyEvent(成功)或ApplicationFailedEvent(失败)事件

至此,Spring boot的基础启动过程分析完毕,其中的可自定义点也基本明了。

以上加粗位置为spring/springboot留出的可扩展点,基于此进行相应扩展即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值