黑马程序猿 SpringBoot 启动流程笔记

SpringApplication 构造方法

  1. 获取 Bean Definition 来源
  2. 确定 ApplicationContext 的类型
  3. 获取添加 ApplicationContext 的初始化器,这些组件会在 refresh 前被执行 10.4
  4. 获取 application 中的事件监听器,ApplicationEvent 被推送时会回调这些事件处理方法
  5. 进行启动主类推断

SpringApplication run 方法

Spring Application Run Listener 事件流程

  1. starting application 开始启动
  2. environmentPrepared 环境类对象准备完成
  3. contextPrepared ioc 容器准备
  4. contextLoaded 加载 BeanDefinition 完成
  5. started context 容器启动
  6. running application 启动
  7. failed 出现异常,启动失败
Java
复制代码
try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 解析 args 参数,这个对象会被注册为一个 Bean ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 运行环境准备 configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); // 按照 SpringApplication 的构造方法中所确定的 ApplicationContext 类型来创建对应 context 容器 context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 该方法会在 context 初始化前执行 initializer 方法,并从 source 中 加载所有 Bean Definition,这期间会推送 contextprepared 和 contextLoaded 事件 refreshContext(context); // 执行 context 的 refresh 方法 afterRefresh(context, applicationArguments); // 此方法没有逻辑实现,需要开发者继承来实现逻辑 Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); // context 容器启动 callRunners(context, applicationArguments); // 执行 context 容器中 Runner 对象的 run 方法 } catch (Throwable ex) { handleRunFailure(context, ex, listeners); // application 启动失败 throw new IllegalStateException(ex); }

spring boot 结合 spi 机制,将要加载的类写入 spring.factories 文件中,比如 事件处理器中包含的环境准备就绪的事件处理,处理用到的 EnvironmnertPostProcessor 也是 spi 加载的

SpringBoot 一次完整启动流程

构造方法

Java
复制代码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 存储 Bean Difinition 源 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 推断 ApplicationContext 类型 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 通过 SPI 加载默认的 ApplicationInitializer setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 通过 SPI 加载默认的 ApplicationListener this.mainApplicationClass = deduceMainApplicationClass(); // 推断启动类的 class }

run 方法

Java
复制代码
public ConfigurableApplicationContext run(String... args) { ConfigurableApplicationContext context = null; SpringApplicationRunListeners listeners = getRunListeners(args); // 通过 SPI 机制加载 EventPublisherRunListener 对象 listeners.starting(bootstrapContext, this.mainApplicationClass); // 发布 SpringApplication 启动事件 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 封装 args 为 ApplicationArguments 对象 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 准备环境对象 Banner printedBanner = printBanner(environment); // 打印输出 Banner 信息 context = createApplicationContext(); // 根据类型 由不同的 ApplicationContextFactory 创建不同的 ApplicationContext 对象 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 准备 ApplicationContext 对象,执行 ApplicationInitializer 和从所有 Source 加载 BeanDefinition refreshContext(context); // 执行 ApplicationContext 的 refresh 方法 afterRefresh(context, applicationArguments); // 无逻辑,需要继承重写 listeners.started(context, timeTakenToStartup); // 发布 SpringApplication 启动事件 callRunners(context, applicationArguments); // 调用被注册的 CommondLineRunner 和 ArgumentRunner 的 run 方法 return context; }

准备环境对象

Java
复制代码
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 根据 ApplicationContext 类型创建不同类型的 Environment 对象 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 将命令行参数中的 可选择参数加入 Environmnet 对象 ConfigurationPropertySources.attach(environment); // 将配置文件中的参数名称统一格式化按照 ‘-’ 分隔不同单词 listeners.environmentPrepared(bootstrapContext, environment); // 发布环境准备完成事件,相关后处理器对环境对象进行增强 bindToSpringApplication(environment); // 绑定环境中的参数到 SpringApplication 对象中 ConfigurationPropertySources.attach(environment); // 将配置文件中的参数名称统一格式化按照 ‘-’ 分隔不同单词 return environment; }

准备 ApplicationContext 对象

Java
复制代码
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); // 环境对象存入 applyInitializers(context); // 执行初始化器 listeners.contextPrepared(context); // 发布初始化成功事件 // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 将 arguments 添加入 BeanFactory,为以后调用作准备 if (this.lazyInitialization) { // 懒加载 context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set<Object> sources = getAllSources(); load(context, sources.toArray(new Object[0])); // 从所有 Source 中加载 BeanDifinition listeners.contextLoaded(context); }
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP