IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot启动流程源码分析 -> 正文阅读

[Java知识库]SpringBoot启动流程源码分析

springboot version:2.4.5

1 程序入口

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    // 新建一个springboot应用,并调用run方法
   return new SpringApplication(primarySources).run(args);
}

SpringBoot项目启动当然也是main方法作为主程序入口

2 启动过程分析

2.1 创建SpringApplication

通过 new SpringApplication 创建

// SpringApplication应用构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 
    // 入参一般为null,暂不关注
	this.resourceLoader = resourceLoader; 
    // 断言
	Assert.notNull(primarySources, "PrimarySources must not be null"); 
    // 保存启动类
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); 
    // (1) 判断spring应用类型 
	this.webApplicationType = WebApplicationType.deduceFromClasspath(); 
    // (2) 从spring.factories中获取BootstrapRegistryInitializer实现类并保存在bootstrapRegistryInitializers中
    // List<BootstrapRegistryInitializer> bootstrapRegistryInitializers 是一个list
	this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); 
    // (3) 获取ApplicationContextInitializer并保存
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // (4) 获取ApplicationListener并保存
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // (5) 推断main方法
	this.mainApplicationClass = deduceMainApplicationClass();
}

上文(1)处

// 自动判断当前工程是什么类型的application
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
      && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
   return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
   if (!ClassUtils.isPresent(className, null)) {
      return WebApplicationType.NONE;
   }
}
// 一般是servlet应用,也就是web应用
return WebApplicationType.SERVLET;
}

上文(2)处

private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
// 获取Bootstrapper实现类并调用initialize方法
getSpringFactoriesInstances(Bootstrapper.class).stream()
      .map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
      .forEach(initializers::add);
 // 通过这个getSpringFactoriesInstances方法获取BootstrapRegistryInitializer
 // 启动过程中这个方法多次用来获取spring.factories中获取配置
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}

上文(3)处

private Class<?> deduceMainApplicationClass() {
   try {
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         if ("main".equals(stackTraceElement.getMethodName())) {
             // 返回main方法的类
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue
   }
   return null;
}

2.2 SpringApplication的run方法

// 启动上面创建的SpringApplication
public ConfigurableApplicationContext run(String... args) {
   // 状态表
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   // (6) 创建DefaultBootstrapContext,
   // 创建过程中会调用(2)bootstrapRegistryInitializers中的RegistryInitializer
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   // (7) 设置headlerss属性(暂时没明白headless干嘛用的)
   configureHeadlessProperty();
   // (8) 获取并保存SpringApplicationRunListener
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // (9) 遍历调用(6)中获取到的SpringApplicationRunListeners的starting方法
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      // (10) args是main方法的入参,在这里保存起来
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // (11) 准备环境
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      // 配置忽略的bean info (暂不知干嘛,不影响启动流程)
      configureIgnoreBeanInfo(environment);
      // 打印banner 1:getImageBannerspring.banner.image.location 2:getTextBanner banner.txt
      Banner printedBanner = printBanner(environment);
      // (12) 创建spring ioc 容器 
      // 根据webApplicationType创建 servlet 对应AnnotationConfigServletWebServerApplicationContext
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
      // (13) prepareContext
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      // (14) 刷新容器 将会调用spring的容器刷新方法
      refreshContext(context);
      // (15) 暂时为空方法 Called after the context has been refreshed.
      afterRefresh(context, applicationArguments);
      // 状态表停止
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // (16) 遍历调用(4)中listene的started
      listeners.started(context);
      // (17) call Runners,Runners有两种分别为ApplicationRunner和CommandLineRunner
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      // (18) 捕获启动流程中的异常
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      // (19) 遍历调用listener的running方法
      listeners.running(context);
   }
   catch (Throwable ex) {
      // (20) 捕获(19中的异常),执行(18)一样的逻辑
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

上文(6)处

private DefaultBootstrapContext createBootstrapContext() {
   DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
   // 遍历调用RegistryInitializer的初始化方法
   this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
   return bootstrapContext;
}

上文(7)处

private void configureHeadlessProperty() {
   // SYSTEM_PROPERTY_JAVA_AWT_HEADLESS="java.awt.headless"
   // this.headless默认为true
   System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
         System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

上文(8)处

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   // 也是从spring.factories中获取
   return new SpringApplicationRunListeners(logger,
         getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
         this.applicationStartup);
}

上文(11)处

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
   // Create the environment 根据(1)中的webApplicationType创建
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   // (11.1) configure the environment 对属性源或配置文件进行细粒度控制。
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   ConfigurationPropertySources.attach(environment);
   // 遍历调用SpringApplicationRunListeners的environmentPrepared方法
   listeners.environmentPrepared(bootstrapContext, environment);
   DefaultPropertiesPropertySource.moveToEnd(environment);
   // 配置active profile
   configureAdditionalProfiles(environment);
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

上文 (11.1) 处

// 对属性源或配置文件进行细粒度控制。
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
   if (this.addConversionService) {
      ConversionService conversionService = ApplicationConversionService.getSharedInstance();
      environment.setConversionService((ConfigurableConversionService) conversionService);
   }
   configurePropertySources(environment, args);
   configureProfiles(environment, args);
}

上文 (13) 处

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   context.setEnvironment(environment);
   // ApplicationContext 的后置处理器
   postProcessApplicationContext(context);
   // 遍历调用(3) 中ApplicationContextInitializer的初始化方法
   applyInitializers(context);
   // 遍历调用(4) 中的 ApplicationListener的contextPrepared方法
   listeners.contextPrepared(context);
   // 发布了一个bootstrapContext close事件
   bootstrapContext.close(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
   // Add boot specific singleton beans
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
   // 将(10)中的启动参数对象注册为bean
   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
   // 注册springBootBanner的bean
   if (printedBanner != null) {
      beanFactory.registerSingleton("springBootBanner", printedBanner);
   }
   if (beanFactory instanceof DefaultListableBeanFactory) {
      // bean的Overrid
      ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   // 默认false
   if (this.lazyInitialization) {
      // 设置beanFactory的后置处理器
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
   }
   // Load the sources
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   load(context, sources.toArray(new Object[0]));
   // // 遍历调用(4) 中的 ApplicationListener的contextLoaded方法
   listeners.contextLoaded(context);
}

上文 (17) 处

private void callRunners(ApplicationContext context, ApplicationArguments args) {
   List<Object> runners = new ArrayList<>();
   // 从容器中获取ApplicationRunner的bean
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   // 从容器中获取CommandLineRunner的bean
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   // runner 进行排序
   AnnotationAwareOrderComparator.sort(runners);
   // 遍历调用
   for (Object runner : new LinkedHashSet<>(runners)) {
      // 这个地方有个神奇的设置,为什么需要将两个runner的回调入参设置的不一样,猜想是兼容
      if (runner instanceof ApplicationRunner) {
         callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
         callRunner((CommandLineRunner) runner, args);
      }
   }
}

上文 (18) 处

private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
      SpringApplicationRunListeners listeners) {
   try {
      try {
         handleExitCode(context, exception);
         if (listeners != null) {
            // 遍历调用listers的failed方法
            listeners.failed(context, exception);
         }
      }
      finally {
         // 通过getSpringFactoriesInstances获取spring.factories中的SpringBootExceptionReporter
         // 并调用SpringBootExceptionReporter的reportException方法
         reportFailure(getExceptionReporters(context), exception);
         if (context != null) {
            // 关闭容器
            context.close();
         }
      }
   }
   catch (Exception ex) {
      logger.warn("Unable to close ApplicationContext", ex);
   }
   ReflectionUtils.rethrowRuntimeException(exception);
}

简单的注释,欢迎大哥指正补充

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:12:16  更:2021-11-22 12:13:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:17:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码