一箭天网络推广,关键字排名优化工具,南宁码科网站建设,敦煌网站做外贸怎样SpringBoot源码系列文章
SpringBoot源码解析(一)#xff1a;启动流程之SpringApplication构造方法
SpringBoot源码解析(二)#xff1a;启动流程之引导上下文DefaultBootstrapContext 目录 前言一、入口二、DefaultBootstrapContext1、BootstrapRegistry接口2、BootstrapCon…SpringBoot源码系列文章
SpringBoot源码解析(一)启动流程之SpringApplication构造方法
SpringBoot源码解析(二)启动流程之引导上下文DefaultBootstrapContext 目录 前言一、入口二、DefaultBootstrapContext1、BootstrapRegistry接口2、BootstrapContext接口3、DefaultBootstrapContext实现类 三、BootstrapRegistryInitializer1、作用及触发时机2、示例 总结 前言 前文深入解析SpringApplication构造方法而接下来的几篇文章将重点介绍run方法的执行逻辑。 SpringBoot版本2.7.18的SpringApplication的run方法的执行逻辑如下本文将详细介绍第一小节创建引导上下文 // SpringApplication类方法
public ConfigurableApplicationContext run(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 new DefaultApplicationArguments(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) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 11.通知监听器应用启动完成listeners.started(context, timeTakenToStartup);// 12.调用应用程序中的 CommandLineRunner 或 ApplicationRunner以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch (Throwable ex) {// 13.处理启动过程中发生的异常并通知监听器handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 14.计算应用启动完成至准备就绪的时间并通知监听器Duration timeTakenToReady Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 处理准备就绪过程中发生的异常handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;
}一、入口
// 1.创建引导上下文用于管理应用启动时的依赖和资源
DefaultBootstrapContext bootstrapContext createBootstrapContext();bootstrapRegistryInitializers就是上一篇文章中在SpringApplication构造方法中创建的引导注册组件初始化器集合查询spring.factories文件没有找到BootstrapRegistryInitializer的实现类调用初始化器的initialize方法参数为bootstrapContext也就是说每个初始化器都会对bootstrapContext进行必要的设置和准备启动时需要的资源和依赖本方法是在run方法最开始调用的也就是说引导注册组件初始化器组件的执行时机最早了 主要内容就是实例化DefaultBootstrapContext以及遍历BootstrapRegistryInitializer集合调用initialize下面详细介绍下这两个类的作用。
// SpringApplication类属性方法// 引导注册初始化器
private ListBootstrapRegistryInitializer bootstrapRegistryInitializers;private DefaultBootstrapContext createBootstrapContext() {// 创建一个 DefaultBootstrapContext 实例用于管理应用启动时的资源和依赖DefaultBootstrapContext bootstrapContext new DefaultBootstrapContext();// 遍历 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以便可供应用程序使用。
public interface BootstrapRegistry {// 注册特定类型到注册表。如果指定的类型已注册且未以单例形式获取则将替换。T void register(ClassT type, InstanceSupplierT instanceSupplier);// 如果尚未存在则注册特定类型到注册表。T void registerIfAbsent(ClassT type, InstanceSupplierT instanceSupplier);// 返回给定类型是否已经注册。T boolean isRegistered(ClassT type);// 返回给定类型的已注册 {link InstanceSupplier}如果没有则返回 null。T InstanceSupplierT getRegisteredInstanceSupplier(ClassT type);// 添加 {link ApplicationListener}当 {link BootstrapContext} 关闭且// {link ApplicationContext} 准备就绪时将调用该监听器并传递 {link BootstrapContextClosedEvent}。void addCloseListener(ApplicationListenerBootstrapContextClosedEvent listener);// 提供所需时创建实际实例的供应者。FunctionalInterfaceinterface InstanceSupplierT {// 工厂方法在需要时创建实例。T get(BootstrapContext context);// 返回所提供实例的作用域。default Scope getScope() {return Scope.SINGLETON;}// 返回一个具有更新 {link Scope} 的新 {link InstanceSupplier}。default InstanceSupplierT withScope(Scope scope) {Assert.notNull(scope, Scope must not be null);InstanceSupplierT parent this;return new InstanceSupplierT() {Overridepublic T get(BootstrapContext context) {return parent.get(context);}Overridepublic Scope getScope() {return scope;}};}// 工厂方法用于为给定实例创建 {link InstanceSupplier}。static T InstanceSupplierT of(T instance) {return (registry) - instance;}// 工厂方法用于从 {link Supplier} 创建 {link InstanceSupplier}。static T InstanceSupplierT from(SupplierT supplier) {return (registry) - (supplier ! null) ? supplier.get() : null;}}// 实例的作用域。enum Scope {// 单例实例。 {link InstanceSupplier} 将仅被调用一次并且每次都将返回相同的实例。SINGLETON,// 原型实例。 {link InstanceSupplier} 将在每次需要实例时调用。PROTOTYPE}
}总结用于注册引导阶段的组件在应用启动时通过register方法动态添加对象
2、BootstrapContext接口 一个简单的引导上下文在启动和处理环境配置期间可用直到ApplicationContext准备好为止。提供对单例的惰性访问这些单例的创建成本可能很高或者需要在ApplicationContext可用之前共享。
public interface BootstrapContext {// 如果类型已注册则从上下文中返回实例。如果之前未访问过该实例则会创建该实例T T get(ClassT type) throws IllegalStateException;// 如果类型已注册则返回上下文中的实例。如果尚未访问该实例则将创建它。// 如果类型未注册则返回指定的替代实例。T T getOrElse(ClassT type, T other);// 如果类型已注册则返回上下文中的实例。如果尚未访问该实例则将创建它。// 如果类型未注册则使用指定的供应者提供的实例。T T getOrElseSupply(ClassT type, SupplierT other);// 如果类型已注册则返回上下文中的实例。如果尚未访问该实例则将创建它。// 如果类型未注册则抛出由供应者提供的异常。T, X extends Throwable T getOrElseThrow(ClassT type, Supplier? extends X exceptionSupplier) throws X;// 返回给定类型是否存在注册T boolean isRegistered(ClassT type);}总结用于提供对引导阶段注册组件的只读访问一旦BootstrapRegistry注册完成并构建成BootstrapContext所有组件可以通过get方法被安全地访问直到应用启动完成。
3、DefaultBootstrapContext实现类
ConfigurableBootstrapContext是一个空接口所以直接看核心内容DefaultBootstrapContext
public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {
}DefaultBootstrapContext是一个实现了ConfigurableBootstrapContext接口的类主要用于管理应用启动过程中的实例供应者和实例提供了注册、获取、关闭监听等功能。以下是主要功能的总结
实例供应者管理 使用MapClass?, InstanceSupplier? instanceSuppliers来存储类型到实例供应者的映射可以通过register和registerIfAbsent方法来注册实例供应者register方法支持覆盖现有的实例供应者而registerIfAbsent则仅在类型未注册的情况下注册实例供应者 实例管理 使用MapClass?, Object instances存储已创建的实例提供get、getOrElse、getOrElseSupply等方法来获取实例。如果实例尚未创建则调用相应的实例供应者来创建实例并在单例作用域下将其存储 事件管理(后面文章调用时候细讲) 使用ApplicationEventMulticaster来管理事件的发布和监听提供addCloseListener方法添加关闭监听器并在close方法中发布BootstrapContextClosedEvent事件
public class DefaultBootstrapContext implements ConfigurableBootstrapContext {// 存储实例供应者的映射private final MapClass?, InstanceSupplier? instanceSuppliers new HashMap();// 存储已创建实例的映射private final MapClass?, Object instances new HashMap();// 事件广播器用于发布应用事件private final ApplicationEventMulticaster events new SimpleApplicationEventMulticaster();Overridepublic T void register(ClassT type, InstanceSupplierT instanceSupplier) {// 注册特定类型的实例供应者register(type, instanceSupplier, true);}Overridepublic T void registerIfAbsent(ClassT type, InstanceSupplierT instanceSupplier) {// 如果尚未注册则注册特定类型的实例供应者register(type, instanceSupplier, false);}private T void register(ClassT type, InstanceSupplierT 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 boolean isRegistered(ClassT type) {// 检查给定类型是否已注册synchronized (this.instanceSuppliers) {return this.instanceSuppliers.containsKey(type);}}OverrideSuppressWarnings(unchecked)public T InstanceSupplierT getRegisteredInstanceSupplier(ClassT type) {// 返回已注册的实例供应者synchronized (this.instanceSuppliers) {return (InstanceSupplierT) this.instanceSuppliers.get(type);}}Overridepublic T T get(ClassT type) throws IllegalStateException {// 获取指定类型的实例如果未注册则抛出异常return getOrElseThrow(type, () - new IllegalStateException(type.getName() has not been registered));}Overridepublic T T getOrElse(ClassT type, T other) {// 获取指定类型的实例如果未注册则返回其他提供的实例return getOrElseSupply(type, () - other);}Overridepublic T T getOrElseSupply(ClassT type, SupplierT other) {// 尝试获取指定类型的实例如果未注册则调用其他供应者synchronized (this.instanceSuppliers) {InstanceSupplier? instanceSupplier this.instanceSuppliers.get(type);return (instanceSupplier ! null) ? getInstance(type, instanceSupplier) : other.get();}}Overridepublic T, X extends Throwable T getOrElseThrow(ClassT type, Supplier? extends X exceptionSupplier) throws X {// 尝试获取指定类型的实例如果未注册则抛出由供应者提供的异常synchronized (this.instanceSuppliers) {InstanceSupplier? instanceSupplier this.instanceSuppliers.get(type);if (instanceSupplier null) {throw exceptionSupplier.get();}return getInstance(type, instanceSupplier);}}SuppressWarnings(unchecked)private T T getInstance(ClassT 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;}Overridepublic void addCloseListener(ApplicationListenerBootstrapContextClosedEvent listener) {// 添加关闭监听器当 BootstrapContext 关闭时触发this.events.addApplicationListener(listener);}/*** 当 {link BootstrapContext} 关闭且 {link ApplicationContext} 已准备好时调用的方法。* param applicationContext 已准备好的上下文*/public void close(ConfigurableApplicationContext applicationContext) {// 发布 BootstrapContext 关闭事件this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));}
}三、BootstrapRegistryInitializer
1、作用及触发时机
回调接口用于在BootstrapRegistry(对象注册表)使用之前进行初始化作用应用程序启动的早期阶段进行必要的初始化和配置
FunctionalInterface
public interface BootstrapRegistryInitializer {// 此方法在应用启动过程中被调用允许实现者向注册表注册必要的组件或服务。// 注册的组件随后可以在应用上下文中访问。实现者应仅注册应用所需的类型。void initialize(BootstrapRegistry registry);
}引导注册组件初始化器BootstrapRegistryInitializer在SpringApplication的构造方法中通过查找META-INF/spring.factories文件进行加载然后在引导上下文实例创建完成后遍历并调用所有BootstrapRegistryInitializer#initialize方法。 普通SpringBoot项目没有其实现找了个SpringCloud项目看了下有两个 2、示例
自定义BootstrapRegistryInitializer
public class MyBootstrapRegistryInitializer implements BootstrapRegistryInitializer {Overridepublic void initialize(BootstrapRegistry registry) {// 注册一个自定义服务registry.register(MyCustomService.class, context - new MyCustomService());System.out.println(MyBootstrapRegistryInitializer已注册);}
}
class MyCustomService {
}在META-INF/spring.factories文件中添加对自定义初始化器的配置
org.springframework.boot.BootstrapRegistryInitializercom.xc.config.MyBootstrapRegistryInitializer启动服务 psBootstrapRegistryInitializer是SpringBoot第一个扩展点注册组件 总结
引导上下文DefaultBootstrapContext创建在run方法的最初阶段被实例化并通过BootstrapRegistryInitializer(第一个注册组件扩展点)进行必要的初始化确保应用启动时所需的资源和依赖得到妥善管理BootstrapRegistry的作用该接口作为对象注册表允许在应用启动早期阶段进行组件的注册和管理提供了对高成本实例的惰性访问BootstrapContext的角色作为引导上下文的只读访问接口它确保注册的组件能够安全、可靠地在应用上下文准备好之前被访问