2.1 BootstrapContext2.1.1 源码初识public interface BootstrapContext { <T> T get(Class<T> type) throws 和 BootstrapContext 接口。 isRegistered 方法比较特殊,它在 BootstrapRegistry 和 BootstrapContext 接口中均可以看到。 } 从 2.1 小节,我们了解了 BootstrapContext 的 4 个获取方法。 三、总结本篇 Huazie 带大家深入了解了 BootstrapContext 及其默认实现,这些内容对我们理解 Spring Boot 的启动引导过程至关重要。
其中涉及到了 BootstrapContext 的部分使用场景,那本篇就向大家演示下 Spring Boot 启动过程中如何使用引用上下文 BootstrapContext 及其默认实现 。 2.1 BootstrapContext 在 《深入 BootstrapContext 及其默认实现》 中,Huazie 详细介绍了引导上下文 BootstrapContext 及其默认实现 DefaultBootstrapContext ,以便后续在实际的场景中通过 BootstrapContext 来获取。 2.3 BootstrapContext 的实际使用场景 首先我们需要通过源码来明确下需要 添加哪些内容,哪些场景和引导上下文有关? 2.4 实际使用演示 BootstrapContext 的实际使用场景已经在 2.3 中介绍,下面 Huazie 就带大家实操下。
// 这一步确保每个 initializer 都可以对 bootstrapContext 进行相应的配置, // 为应用程序的启动过程准备所需的资源。 this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)) ; // 返回已完成初始化的 DefaultBootstrapContext 对象 return bootstrapContext; } 二、DefaultBootstrapContext T get(BootstrapContext context); // 返回所提供实例的作用域。 public interface BootstrapContext { // 如果类型已注册,则从上下文中返回实例。
2、创建启动上下文 DefaultBootstrapContext = createBootstrapContext(); BootstrapContext:启动上下文,生命周期同 BootstrapRegistry DefaultBootstrapContext 继承了 BootstrapContext、BootstrapRegistry。 用于 BootstrapRegistry 初始化。 listeners.environmentPrepared(bootstrapContext, environment) environment-prepared step。 12、ApplicationContext 准备 prepareContext() private void prepareContext(DefaultBootstrapContext bootstrapContext ApplicationContextInitializer 应用 contextPrepared 事件 【spring.boot.application.context-prepared】step BootstrapContext
本篇就让我们自定义 BootstrapRegistryInitializer 接口实现,以此来执行自定义的初始化操作【如注册自定义的 Bean、添加 BootstrapContext 关闭监听器】。 POJO 类,含两个成员变量:名称 name 和年龄 age registry.register(User.class, context -> new User("Huazie", 18)); // 添加 BootstrapContext bootstrapContext = event.getBootstrapContext(); if (bootstrapContext.isRegistered(User.class )) { System.out.println("BootstrapContext关闭时获取User:" + bootstrapContext.get(User.class)); 在 DemoBootstrapContextClosedListener 中,我们看到了 BootstrapContext 的使用,显然这里涉及到了引导上下文的实际使用场景,由于篇幅受限,将在下篇介绍
context.setApplicationStartup(this.applicationStartup); // 设置应用启动状态 prepareContext(bootstrapContext , environment); void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment , environment)); } 继续 listener.environmentPrepared(bootstrapContext, environment) 发布事件 @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment ) { this.initialMulticaster.multicastEvent( new ApplicationEnvironmentPreparedEvent(bootstrapContext
StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 创建启动上下文对象 DefaultBootstrapContext bootstrapContext 第一步:获取并启动监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext context.setApplicationStartup(this.applicationStartup); // 第五步:spring容器前置处理 prepareContext(bootstrapContext { } } run方法第二步:准备环境 /** * 创建并配置SpringBooty应用j将要使用的Environment * * @param listeners * @param bootstrapContext prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext
// run方法执行时立马执行;对应事件类型ApplicationStartingEvent void starting(ConfigurableBootstrapContext bootstrapContext ;对应事件类型ApplicationEnvironmentPreparedEvent void environmentPrepared(ConfigurableBootstrapContext bootstrapContext "spring.boot.application.environment-prepared", (listener) -> listener.environmentPrepared(bootstrapContext ) { multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args )); } @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext
addCloseListener(ApplicationListener) 方法可用于添加监听器,当 BootstrapContext 已关闭并且 ApplicationContext 完全准备好时,该监听器可以执行操作 (initializer) -> initializer.initialize(bootstrapContext) : Lambda 表达式,这是 Java 8 引入的一个新特性,允许以更简洁的方式表示匿名方法 它表示一个接受BootstrapRegistryInitializer 类型参数 initializer,并调用其 initialize(bootstrapContext) 方法的功能。 简而言之,对于 this.bootstrapRegistryInitializers 列表中的每个 BootstrapRegistryInitializer,使用当前的 bootstrapContext 这里的 bootstrapContext 其实就是 BootstrapRegistry 注册表的一个默认实现 DefaultBootstrapContext 。
// 计时器开始 stopWatch.start(); // 创建启动上下文对象 DefaultBootstrapContext bootstrapContext // 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext 下一步就是开始启动了listeners.starting();我们往下跟源码看 @Override public void starting(ConfigurableBootstrapContext bootstrapContext ) { this.initialMulticaster .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application 同上面启动监听事件,这次的环境准备也是同样的代码 @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext
启动SpringApplicationRunListeners实例,循环调用SpringApplicationRunListener实例的starting方法 listeners.starting(bootstrapContext //准备应用程序上下文,这里会调用SpringApplicationRunListener实例的contextPrepared和contextLoaded方法 prepareContext(bootstrapContext )); return bootstrapContext; } configureHeadlessProperty(),配置headless private void configureHeadlessProperty this.applicationStartup),设置启动期间的记录类 默认设置为DefaultApplicationStartup,是一个空操作的记录类,支持显示覆盖 prepareContext(bootstrapContext applicationArguments, printedBanner),准备应用程序上下文 private void prepareContext(DefaultBootstrapContext bootstrapContext
run(String... args) { long startTime = System.nanoTime(); // 类加载上线文 DefaultBootstrapContext bootstrapContext SpringApplicationRunListeners listeners = getRunListeners(args); // 开始监听 listeners.starting(bootstrapContext DefaultApplicationArguments(args); //配置环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext (); context.setApplicationStartup(this.applicationStartup); //初始化工作 prepareContext(bootstrapContext private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext
ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); // 1.创建BootstrapContext DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext 时使用最后在prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner )); return bootstrapContext;}其实就是使用了bootstrapRegistryInitializers,依次调用initializer.initialize方法初始化, ,this.mainApplicationClass)方法void starting(ConfigurableBootstrapContext bootstrapContext, Class<?
SpringApplicationRunListeners listeners = getRunListeners(args); // 获取运行监听器 listeners.starting(bootstrapContext context.setApplicationStartup(this.applicationStartup); // 设置应用启动状态 prepareContext(bootstrapContext void starting(ConfigurableBootstrapContext bootstrapContext, Class<? doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext) ) { this.initialMulticaster .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application
创建并启动计时监控类 StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext 运行监听器并发布应用启动事件 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext DefaultApplicationArguments(args); // 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 准备应用上下文 prepareContext(bootstrapContext
创建一个bootStrapContext容器,并基于initializers中的initializer回调初始化 2. 配置java.awt.headless属性 3. ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext ); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(bootstrapContext DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); this.prepareContext(bootstrapContext
BootstrapContextClosedEvent> listener); @FunctionalInterface interface InstanceSupplier<T> { T get(BootstrapContext 只有一个参数:ApplicationListener<BootstrapContextClosedEvent> listener :待添加的监听器该方法用于添加一个 ApplicationListener,当 BootstrapContext 2.7.1 get 方法get 方法,只包含一个参数:BootstrapContext context :BootstrapContext 是一个用于获取其他引导实例的上下文该方法是工厂方法,用于在需要时创建实例 这里采用了 Java 8 的 Lambda 表达式,也相当于如下的写法:return new InstanceSupplier<T>() { @Override public T get(BootstrapContext 这里也是用了 Java 8 的 Lambda 表达式,相当于如下的写法:return new InstanceSupplier<T>() { @Override public T get(BootstrapContext
EventPublishingRunListener类中 public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext (DeferredLogFactory.class, logFactory); //向argumentResolver对象中添加ConfigurableBootstrapContext.class和bootstrapContext ); // // 向argumentResolver对象中添加BootstrapRegistry.class和bootstrapContext,获取更新后的argumentResolver对象 argumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext); 通过this.loader.load方法加载EnvironmentPostProcessor 类型的对象,参数为argumentResolver argumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext
stopWatch = new StopWatch(); // 创建一个计时器 stopWatch.start(); // 开始计时 DefaultBootstrapContext bootstrapContext SpringApplicationRunListeners listeners = getRunListeners(args); // 获取运行监听器 listeners.starting(bootstrapContext context.setApplicationStartup(this.applicationStartup); // 设置应用启动状态 prepareContext(bootstrapContext new IllegalStateException(ex); // 抛出异常 } return context; // 返回应用上下文 } 我们重点看 prepareContext(bootstrapContext bootstrapContext.close(context); // 如果需要记录启动信息 if (this.logStartupInfo) { // 记录启动信息
// 它记录了开始时间,结束时间,当前线程名称 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 创建bootstrapContext 启动上下文对象 // 并执行启动初始程序方法(BootstrapRegistryInitializer.initialize) DefaultBootstrapContext bootstrapContext listeners = getRunListeners(args); // 发布`ApplicationStartingEvent`事件并记录步骤 listeners.starting(bootstrapContext 发布ApplicationPreparedEvent事件 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments , this.mainApplicationClass); void starting(ConfigurableBootstrapContext bootstrapContext, Class<?