0


SpringBoot源码解析(二):引导上下文DefaultBootstrapContext

SpringBoot源码系列文章

SpringBoot源码解析(一):SpringApplication构造方法

SpringBoot源码解析(二):引导上下文DefaultBootstrapContext


目录

前言

**前文深入解析SpringApplication构造方法,而接下来的几篇文章将重点介绍

run

方法的执行逻辑。**

在这里插入图片描述

**

SpringBoot版本2.7.18

的SpringApplication的run方法的执行逻辑如下,本文将详细介绍

第一小节:创建引导上下文

**

// SpringApplication类方法publicConfigurableApplicationContextrun(String... args){// 记录应用启动的开始时间long startTime =System.nanoTime();// 1.创建引导上下文,用于管理应用启动时的依赖和资源DefaultBootstrapContext bootstrapContext =createBootstrapContext();ConfigurableApplicationContext context =null;// 配置无头模式属性,以支持在无图形环境下运行// 将系统属性 java.awt.headless 设置为 trueconfigureHeadlessProperty();// 2.获取Spring应用启动监听器,用于在应用启动的各个阶段执行自定义逻辑SpringApplicationRunListeners listeners =getRunListeners(args);// 3.发布开始事件、通知ApplicationListener监听器
    listeners.starting(bootstrapContext,this.mainApplicationClass);try{// 4.解析应用参数ApplicationArguments applicationArguments =newDefaultApplicationArguments(args);// 5.准备应用环境,包括读取配置文件和设置环境变量ConfigurableEnvironment environment =prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置是否忽略 BeanInfo,以加快启动速度configureIgnoreBeanInfo(environment);// 6.打印启动BannerBanner printedBanner =printBanner(environment);// 7.创建应用程序上下文
        context =createApplicationContext();// 设置应用启动的上下文,用于监控和管理启动过程
        context.setApplicationStartup(this.applicationStartup);// 8.准备应用上下文,包括加载配置、添加 Bean 等prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 9.刷新上下文,完成 Bean 的加载和依赖注入refreshContext(context);// 10.刷新后的一些操作,如事件发布等afterRefresh(context, applicationArguments);// 计算启动应用程序的时间,并记录日志Duration timeTakenToStartup =Duration.ofNanos(System.nanoTime()- startTime);if(this.logStartupInfo){newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 11.通知监听器应用启动完成
        listeners.started(context, timeTakenToStartup);// 12.调用应用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch(Throwable ex){// 13.处理启动过程中发生的异常,并通知监听器handleRunFailure(context, ex, listeners);thrownewIllegalStateException(ex);}try{// 14.计算应用启动完成至准备就绪的时间,并通知监听器Duration timeTakenToReady =Duration.ofNanos(System.nanoTime()- startTime);
        listeners.ready(context, timeTakenToReady);}catch(Throwable ex){// 处理准备就绪过程中发生的异常handleRunFailure(context, ex,null);thrownewIllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;}

一、入口

// 1.创建引导上下文,用于管理应用启动时的依赖和资源DefaultBootstrapContext bootstrapContext =createBootstrapContext();
  • bootstrapRegistryInitializers就是上一篇文章中在SpringApplication构造方法中创建的引导注册组件初始化器集合(查询spring.factories文件,没有找到BootstrapRegistryInitializer的实现类)
  • 调用初始化器的initialize方法,参数为bootstrapContext,也就是说每个初始化器都会对bootstrapContext进行必要的设置和准备(启动时需要的资源和依赖
  • 本方法是在run方法最开始调用的,也就是说引导注册组件初始化器组件的执行时机最早

**主要内容就是实例化

DefaultBootstrapContext

以及遍历

BootstrapRegistryInitializer

集合调用initialize,下面详细介绍下这两个类的作用。**

// SpringApplication类属性方法// 引导注册初始化器privateList<BootstrapRegistryInitializer> bootstrapRegistryInitializers;privateDefaultBootstrapContextcreateBootstrapContext(){// 创建一个 DefaultBootstrapContext 实例,用于管理应用启动时的资源和依赖DefaultBootstrapContext bootstrapContext =newDefaultBootstrapContext();// 遍历 bootstrapRegistryInitializers 集合中的每个 initializer,// 并调用它们的 initialize 方法,将 bootstrapContext 作为参数传入。// 这一步确保每个 initializer 都可以对 bootstrapContext 进行相应的配置,// 为应用程序的启动过程准备所需的资源。this.bootstrapRegistryInitializers.forEach((initializer)-> initializer.initialize(bootstrapContext));// 返回已完成初始化的 DefaultBootstrapContext 对象return bootstrapContext;}

二、DefaultBootstrapContext

**DefaultBootstrapContext作为SpringBoot启动过程中的核心组件,负责

环境配置

资源管理

生命周期管理

,确保应用程序的顺利启动和运行。理解其作用有助于开发者更好地掌握SpringBoot的内部机制。**

类图如下:

在这里插入图片描述

1、BootstrapRegistry接口

**一个简单的

对象注册表

,在启动和处理环境配置期间可用,直到

ApplicationContext

准备好为止。提供对单例的惰性访问,这些单例的创建成本可能很高,或者需要在ApplicationContext可用之前共享。**

**注册表使用

Class

作为键,这意味着只能存储给定类型的

单个实例

。**

addCloseListener(ApplicationListener)方法可用于添加监听器,当BootstrapContext关闭且ApplicationContext已准备好时,该监听器可以执行某些操作。例如,实例可以选择将自身注册为常规SpringBean,以便可供应用程序使用。

publicinterfaceBootstrapRegistry{// 注册特定类型到注册表。如果指定的类型已注册且未以单例形式获取,则将替换。<T>voidregister(Class<T> type,InstanceSupplier<T> instanceSupplier);// 如果尚未存在,则注册特定类型到注册表。<T>voidregisterIfAbsent(Class<T> type,InstanceSupplier<T> instanceSupplier);// 返回给定类型是否已经注册。<T>booleanisRegistered(Class<T> type);// 返回给定类型的已注册 {@link InstanceSupplier},如果没有则返回 null。<T>InstanceSupplier<T>getRegisteredInstanceSupplier(Class<T> type);// 添加 {@link ApplicationListener},当 {@link BootstrapContext} 关闭且// {@link ApplicationContext} 准备就绪时,将调用该监听器,并传递 {@link BootstrapContextClosedEvent}。voidaddCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);// 提供所需时创建实际实例的供应者。@FunctionalInterfaceinterfaceInstanceSupplier<T>{// 工厂方法,在需要时创建实例。Tget(BootstrapContext context);// 返回所提供实例的作用域。defaultScopegetScope(){returnScope.SINGLETON;}// 返回一个具有更新 {@link Scope} 的新 {@link InstanceSupplier}。defaultInstanceSupplier<T>withScope(Scope scope){Assert.notNull(scope,"Scope must not be null");InstanceSupplier<T> parent =this;returnnewInstanceSupplier<T>(){@OverridepublicTget(BootstrapContext context){return parent.get(context);}@OverridepublicScopegetScope(){return scope;}};}// 工厂方法,用于为给定实例创建 {@link InstanceSupplier}。static<T>InstanceSupplier<T>of(T instance){return(registry)-> instance;}// 工厂方法,用于从 {@link Supplier} 创建 {@link InstanceSupplier}。static<T>InstanceSupplier<T>from(Supplier<T> supplier){return(registry)->(supplier !=null)? supplier.get():null;}}// 实例的作用域。enumScope{// 单例实例。 {@link InstanceSupplier} 将仅被调用一次,并且每次都将返回相同的实例。
        SINGLETON,// 原型实例。 {@link InstanceSupplier} 将在每次需要实例时调用。
        PROTOTYPE
    }}

总结:用于注册引导阶段的组件,在应用启动时通过register方法动态添加对象

2、BootstrapContext接口

**一个简单的

引导上下文

,在启动和处理环境配置期间可用,直到

ApplicationContext

准备好为止。提供对单例的惰性访问,这些单例的创建成本可能很高,或者需要在ApplicationContext可用之前共享。**

publicinterfaceBootstrapContext{// 如果类型已注册,则从上下文中返回实例。如果之前未访问过该实例,则会创建该实例<T>Tget(Class<T> type)throwsIllegalStateException;// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则返回指定的替代实例。<T>TgetOrElse(Class<T> type,T other);// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则使用指定的供应者提供的实例。<T>TgetOrElseSupply(Class<T> type,Supplier<T> other);// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则抛出由供应者提供的异常。<T,XextendsThrowable>TgetOrElseThrow(Class<T> type,Supplier<?extendsX> exceptionSupplier)throwsX;// 返回给定类型是否存在注册<T>booleanisRegistered(Class<T> type);}

总结:用于提供对引导阶段注册组件的只读访问,一旦BootstrapRegistry注册完成并构建成BootstrapContext,所有组件可以通过get方法被安全地访问,直到应用启动完成。

3、DefaultBootstrapContext实现类

  • ConfigurableBootstrapContext是一个空接口,所以直接看核心内容DefaultBootstrapContext
publicinterfaceConfigurableBootstrapContextextendsBootstrapRegistry,BootstrapContext{}

**

DefaultBootstrapContext

是一个实现了

ConfigurableBootstrapContext

接口的类,主要用于管理应用启动过程中的

实例供应者

实例

,提供了注册、获取、关闭监听等功能。以下是主要功能的总结:**

  1. 实例供应者管理: - 使用Map<Class<?>, InstanceSupplier<?>> instanceSuppliers来存储类型到实例供应者的映射,可以通过registerregisterIfAbsent方法来注册实例供应者- register方法支持覆盖现有的实例供应者,而registerIfAbsent则仅在类型未注册的情况下注册实例供应者
  2. 实例管理: - 使用Map<Class<?>, Object> instances存储已创建的实例- 提供getgetOrElsegetOrElseSupply等方法来获取实例。如果实例尚未创建,则调用相应的实例供应者来创建实例,并在单例作用域下将其存储
  3. **事件管理(后面文章调用时候细讲)**: - 使用ApplicationEventMulticaster来管理事件的发布和监听- 提供addCloseListener方法添加关闭监听器,并在close方法中发布BootstrapContextClosedEvent事件
publicclassDefaultBootstrapContextimplementsConfigurableBootstrapContext{// 存储实例供应者的映射privatefinalMap<Class<?>,InstanceSupplier<?>> instanceSuppliers =newHashMap<>();// 存储已创建实例的映射privatefinalMap<Class<?>,Object> instances =newHashMap<>();// 事件广播器,用于发布应用事件privatefinalApplicationEventMulticaster events =newSimpleApplicationEventMulticaster();@Overridepublic<T>voidregister(Class<T> type,InstanceSupplier<T> instanceSupplier){// 注册特定类型的实例供应者register(type, instanceSupplier,true);}@Overridepublic<T>voidregisterIfAbsent(Class<T> type,InstanceSupplier<T> instanceSupplier){// 如果尚未注册,则注册特定类型的实例供应者register(type, instanceSupplier,false);}private<T>voidregister(Class<T> type,InstanceSupplier<T> instanceSupplier,boolean replaceExisting){// 检查类型和实例供应者是否为空Assert.notNull(type,"Type must not be null");Assert.notNull(instanceSupplier,"InstanceSupplier must not be null");synchronized(this.instanceSuppliers){// 检查类型是否已注册boolean alreadyRegistered =this.instanceSuppliers.containsKey(type);if(replaceExisting ||!alreadyRegistered){// 确保实例尚未创建Assert.state(!this.instances.containsKey(type),()-> type.getName()+" has already been created");// 注册实例供应者this.instanceSuppliers.put(type, instanceSupplier);}}}@Overridepublic<T>booleanisRegistered(Class<T> type){// 检查给定类型是否已注册synchronized(this.instanceSuppliers){returnthis.instanceSuppliers.containsKey(type);}}@Override@SuppressWarnings("unchecked")public<T>InstanceSupplier<T>getRegisteredInstanceSupplier(Class<T> type){// 返回已注册的实例供应者synchronized(this.instanceSuppliers){return(InstanceSupplier<T>)this.instanceSuppliers.get(type);}}@Overridepublic<T>Tget(Class<T> type)throwsIllegalStateException{// 获取指定类型的实例,如果未注册则抛出异常returngetOrElseThrow(type,()->newIllegalStateException(type.getName()+" has not been registered"));}@Overridepublic<T>TgetOrElse(Class<T> type,T other){// 获取指定类型的实例,如果未注册则返回其他提供的实例returngetOrElseSupply(type,()-> other);}@Overridepublic<T>TgetOrElseSupply(Class<T> type,Supplier<T> other){// 尝试获取指定类型的实例,如果未注册则调用其他供应者synchronized(this.instanceSuppliers){InstanceSupplier<?> instanceSupplier =this.instanceSuppliers.get(type);return(instanceSupplier !=null)?getInstance(type, instanceSupplier): other.get();}}@Overridepublic<T,XextendsThrowable>TgetOrElseThrow(Class<T> type,Supplier<?extendsX> exceptionSupplier)throwsX{// 尝试获取指定类型的实例,如果未注册则抛出由供应者提供的异常synchronized(this.instanceSuppliers){InstanceSupplier<?> instanceSupplier =this.instanceSuppliers.get(type);if(instanceSupplier ==null){throw exceptionSupplier.get();}returngetInstance(type, instanceSupplier);}}@SuppressWarnings("unchecked")private<T>TgetInstance(Class<T> type,InstanceSupplier<?> instanceSupplier){// 获取实例,如果尚未创建则调用实例供应者T instance =(T)this.instances.get(type);if(instance ==null){
            instance =(T) instanceSupplier.get(this);// 如果作用域为单例,则存储该实例if(instanceSupplier.getScope()==Scope.SINGLETON){this.instances.put(type, instance);}}return instance;}@OverridepublicvoidaddCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener){// 添加关闭监听器,当 BootstrapContext 关闭时触发this.events.addApplicationListener(listener);}/**
     * 当 {@link BootstrapContext} 关闭且 {@link ApplicationContext} 已准备好时调用的方法。
     * @param applicationContext 已准备好的上下文
     */publicvoidclose(ConfigurableApplicationContext applicationContext){// 发布 BootstrapContext 关闭事件this.events.multicastEvent(newBootstrapContextClosedEvent(this, applicationContext));}}

三、BootstrapRegistryInitializer

1、作用及触发时机

  • 回调接口,用于在BootstrapRegistry(对象注册表)使用之前进行初始化
  • 作用:应用程序启动的早期阶段进行必要的初始化配置
@FunctionalInterfacepublicinterfaceBootstrapRegistryInitializer{// 此方法在应用启动过程中被调用,允许实现者向注册表注册必要的组件或服务。// 注册的组件随后可以在应用上下文中访问。实现者应仅注册应用所需的类型。voidinitialize(BootstrapRegistry registry);}

**引导注册组件初始化器BootstrapRegistryInitializer在SpringApplication的构造方法中通过查找

META-INF/spring.factories

文件进行加载,然后在引导上下文实例创建完成后,遍历并调用所有

BootstrapRegistryInitializer#initialize

方法。**

在这里插入图片描述

普通SpringBoot项目没有其实现,找了个SpringCloud项目看了下,有两个

在这里插入图片描述

2、示例

自定义BootstrapRegistryInitializer

publicclassMyBootstrapRegistryInitializerimplementsBootstrapRegistryInitializer{@Overridepublicvoidinitialize(BootstrapRegistry registry){// 注册一个自定义服务
        registry.register(MyCustomService.class, context ->newMyCustomService());System.out.println("MyBootstrapRegistryInitializer已注册");}}classMyCustomService{}

**在

META-INF/spring.factories

文件中添加对自定义初始化器的配置**

org.springframework.boot.BootstrapRegistryInitializer=com.xc.config.MyBootstrapRegistryInitializer

启动服务

在这里插入图片描述

ps:BootstrapRegistryInitializer是SpringBoot第一个扩展点(注册组件)

总结

  • 引导上下文DefaultBootstrapContext创建:在run方法的最初阶段被实例化,并通过BootstrapRegistryInitializer(第一个注册组件扩展点)进行必要的初始化,确保应用启动时所需的资源和依赖得到妥善管理
  • BootstrapRegistry:该接口作为对象注册表,允许在应用启动早期阶段进行组件的注册和管理,提供了对高成本实例的惰性访问
  • BootstrapContext:作为引导上下文的只读访问接口,它确保注册的组件能够安全、可靠地在应用上下文准备好之前被访问
标签: spring boot java 后端

本文转载自: https://blog.csdn.net/qq_35512802/article/details/143432645
版权归原作者 冬天vs不冷 所有, 如有侵权,请联系我们删除。

“SpringBoot源码解析(二):引导上下文DefaultBootstrapContext”的评论:

还没有评论