黑马程序猿 SpringBoot 启动流程笔记
SpringApplication 构造方法
- 获取 Bean Definition 来源
- 确定 ApplicationContext 的类型
- 获取添加 ApplicationContext 的初始化器,这些组件会在 refresh 前被执行 10.4
- 获取 application 中的事件监听器,ApplicationEvent 被推送时会回调这些事件处理方法
- 进行启动主类推断
SpringApplication run 方法
Spring Application Run Listener 事件流程
- starting application 开始启动
- environmentPrepared 环境类对象准备完成
- contextPrepared ioc 容器准备
- contextLoaded 加载 BeanDefinition 完成
- started context 容器启动
- running application 启动
- 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个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
