当前位置: 首页 > news >正文

郑州网站备案地址东莞网站推广营销

郑州网站备案地址,东莞网站推广营销,asp网站后台编辑器,qq做我女朋友好吗网站SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…

SpringBoot源码系列文章

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

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

SpringBoot源码解析(三):启动开始阶段

SpringBoot源码解析(四):解析应用参数args

SpringBoot源码解析(五):准备应用环境

SpringBoot源码解析(六):打印Banner

SpringBoot源码解析(七):应用上下文结构体系

SpringBoot源码解析(八):Bean工厂接口体系

SpringBoot源码解析(九):Bean定义接口体系

SpringBoot源码解析(十):应用上下文AnnotationConfigServletWebServerApplicationContext构造方法

SpringBoot源码解析(十一):准备应用上下文


目录

  • 前言
  • 源码入口
  • 一、执行应用上下文初始化器
    • 1、获取上下文初始化器
    • 2、执行初始化器
      • 2.1、DelegatingApplicationContextInitializer
      • 2.2、SharedMetadataReaderFactoryContextInitializer
      • 2.3、ContextIdApplicationContextInitializer
      • 2.4、ConfigurationWarningsApplicationContextInitializer
      • 2.5、RSocketPortInfoApplicationContextInitializer
      • 2.6、ServerPortInfoApplicationContextInitializer
      • 2.7、ConditionEvaluationReportLoggingListener
  • 二、触发应用监听器(上下文准备完成)
  • 三、关闭引导上下文
  • 四、触发应用监听器(上下文加载完成)
  • 总结

前言

  在前文中,我们介绍了应用上下文的构造方法初始化两个组件:注解Bean定义读取器和类路径Bean定义扫描器,接下来,我们将探究下准备应用上下文阶段对外的扩展点

SpringBoot版本2.7.18SpringApplication的run方法的执行逻辑如下,本文将详细介绍第8小节:刷新上下文

// 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);// 启动开始方法(发布开始事件、通知应用监听器ApplicationListener)listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 3.解析应用参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 4.准备应用环境,包括读取配置文件和设置环境变量ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置是否忽略 BeanInfo,以加快启动速度configureIgnoreBeanInfo(environment);// 5.打印启动BannerBanner printedBanner = printBanner(environment);// 6.创建应用程序上下文context = createApplicationContext();// 设置应用启动的上下文,用于监控和管理启动过程context.setApplicationStartup(this.applicationStartup);// 7.准备应用上下文,包括加载配置、添加 Bean 等prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 8.刷新上下文,完成 Bean 的加载和依赖注入refreshContext(context);// 9.刷新后的一些操作,如事件发布等afterRefresh(context, applicationArguments);// 计算启动应用程序的时间,并记录日志Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 10.通知监听器应用启动完成listeners.started(context, timeTakenToStartup);// 11.调用应用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch (Throwable ex) {// 12.处理启动过程中发生的异常,并通知监听器handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 13.计算应用启动完成至准备就绪的时间,并通知监听器Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 处理准备就绪过程中发生的异常handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;
}

源码入口

// 7.准备应用上下文,包括加载配置、添加 Bean 等
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
/*** 预处理应用上下文,在应用上下文刷新之前执行一系列准备工作。* * @param bootstrapContext  引导上下文,存储启动过程中的关键组件* @param context           Spring 应用上下文 AnnotationConfigServletWebServerApplicationContext * @param environment       Spring 运行环境* @param listeners         Spring 应用运行监听器* @param applicationArguments 应用程序运行参数* @param printedBanner     启动时显示的 Banner*/
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 设置应用环境context.setEnvironment(environment);// 对ApplicationContext进行处理(没啥重要内容,略过)postProcessApplicationContext(context);// 1. 执行应用程序上下文的初始化器applyInitializers(context);// 2. 触发 contextPrepared 事件,通知监听器上下文已准备好listeners.contextPrepared(context);// 3. 关闭引导上下文,因为之后不再需要bootstrapContext.close(context);// 记录应用启动信息(仅在日志启用时)if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 获取 Bean 工厂,并注册特定的单例 Bean(后面章节注册Bean详解)ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 注册命令行参数(使其可被 Spring 容器访问)beanFactory.registerSingleton("springApplicationArguments", applicationArguments);// 注册启动 Banner(如果存在)if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}// 配置 Bean 工厂的属性if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {// 允许/禁止循环依赖(Spring 5 改为默认禁用循环依赖)((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);// 允许/禁止 BeanDefinition 覆盖(默认禁止)if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}}// 如果启用了懒加载,则添加Bean工厂后处理器(推迟 Bean 初始化)// 后面执行Bean工厂后置处理器时候详解if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 添加属性源排序后处理器,确保 `@PropertySource` 注解的顺序正确// @PropertySource 注解让你能够加载外部配置文件,并将配置文件中的属性注入到 Spring 的 Environment 中context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// 加载应用的所有源(配置类、XML 文件、组件扫描等)Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty"); // 这里就是将SpringBoot配置类注册为Bean定义放到bean工厂load(context, sources.toArray(new Object[0]));// 4. 触发 contextLoaded 事件,通知监听器上下文已加载完成listeners.contextLoaded(context);
}

一、执行应用上下文初始化器

protected void applyInitializers(ConfigurableApplicationContext context) {// 遍历所有需要应用到应用上下文的初始化器for (ApplicationContextInitializer initializer : getInitializers()) {// 通过 GenericTypeResolver 解析初始化器的泛型类型参数,确定所需的上下文类型Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);// 断言当前上下文的类型是否符合要求(指定类型、子类或实现类),如果不符合则抛出异常Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");// 使用初始化器对应用上下文进行初始化initializer.initialize(context);}
}

1、获取上下文初始化器

  上下文初始化器是在SpringApplication构造方法中读取spring.factories文件获取的,这里就是将上下文初始化器集合拿来根据Ordered接口@Order排序

// SpringApplication构造方法中读取spring.factories文件获取的
private List<ApplicationContextInitializer<?>> initializers;// 获取应用上下文的初始化器集合
public Set<ApplicationContextInitializer<?>> getInitializers() {// 将初始化器集合转换为一个不可修改的、有序集合并返回return asUnmodifiableOrderedSet(this.initializers);
}// 将一个集合转换为一个不可修改的、有序的 Set
private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {// 将集合转换为列表,以便对其进行排序List<E> list = new ArrayList<>(elements);// 使用 AnnotationAwareOrderComparator 对列表进行排序// 通过Ordered接口或@Order排序list.sort(AnnotationAwareOrderComparator.INSTANCE);// 将排序后的列表转换为 LinkedHashSet,确保元素的顺序被保留return new LinkedHashSet<>(list);
}

debug看下获取到的初始化器

在这里插入图片描述

2、执行初始化器

  执行初始化器调用ApplicationContextInitializer实现类的initialize方法,下面逐一分析。

2.1、DelegatingApplicationContextInitializer

  简单描述一下,就是通过配置文件属性名context.initializer.classes获取到多个初始化器,然后再遍历调用每个初始化器的。

在这里插入图片描述

举例

假设在application.properties或通过命令行参数配置了以下内容:

context.initializer.classes=com.example.MyCustomInitializer,com.example.AnotherInitializer

  Spring在启动时会解析这个属性,并按照顺序实例化并调用 MyCustomInitializer 和 AnotherInitializer 类,这些类都应该实现ApplicationContextInitializer接口,负责在应用上下文初始化时进行自定义操作。

  DelegatingApplicationContextInitializer适用于需要在 Spring 应用程序启动时,按顺序动态加载执行多个不同的应用上下文初始化器的场景,特别是在具有多个模块或复杂配置的应用中。例如,当需要根据不同的环境配置(如开发、测试、生产环境)执行不同的初始化任务,或者在应用启动时灵活地执行自定义的初始化逻辑(如数据库连接配置、安全设置或外部服务的初始化)时,使用DelegatingApplicationContextInitializer可以帮助通过配置文件集中管理多个初始化器,确保它们按照指定的顺序正确执行。

2.2、SharedMetadataReaderFactoryContextInitializer

  SharedMetadataReaderFactoryContextInitializer 是 Spring 框架中的一个初始化器,它在 Spring 应用上下文初始化过程中,负责确保 MetadataReaderFactory 实例在整个上下文中共享,避免每次进行类路径扫描时都重新创建该工厂实例。MetadataReaderFactory主要用于读取和解析类的元数据,尤其是在注解扫描过程中,例如扫描 @Component, @Service, @Repository 等注解。通过共享MetadataReaderFactory,SharedMetadataReaderFactoryContextInitializer提高了类路径扫描的效率,减少了内存消耗和性能开销,尤其在大型或复杂的 Spring 应用中,能够加速启动过程。

2.3、ContextIdApplicationContextInitializer

  ContextIdApplicationContextInitializer 是 Spring 框架中的一个初始化器类,主要用于为 Spring 应用上下文生成一个唯一的 ID,并将其设置到应用上下文的环境中。这个 ID 通常用于标识不同的应用上下文实例,尤其在有多个 Spring 应用上下文存在的情况下,可以帮助区分它们。

2.4、ConfigurationWarningsApplicationContextInitializer

  ConfigurationWarningsApplicationContextInitializer 是 Spring 框架中的一个应用上下文初始化器,它用于在 Spring 应用程序启动时检查并发出有关配置方面的警告,尤其是关于弃用的配置潜在不推荐的配置。它的主要作用是在应用上下文初始化期间,帮助开发者识别不再推荐使用的配置或可能导致问题的配置方式。

2.5、RSocketPortInfoApplicationContextInitializer

  RSocketPortInfoApplicationContextInitializer 是一个 Spring 应用上下文初始化器,专门用于确保RSocket协议相关的端口信息在 Spring 应用启动时得到正确配置和初始化,特别适用于使用 RSocket 协议进行高效、双向通信的应用场景,如微服务架构和实时通信应用。

2.6、ServerPortInfoApplicationContextInitializer

  ServerPortInfoApplicationContextInitializer是一个确保在 Spring 启动时正确加载、处理和应用服务器端口信息的初始化器,它在处理动态端口配置、跨环境配置或微服务架构中的端口共享方面尤其有用。

2.7、ConditionEvaluationReportLoggingListener

  ConditionEvaluationReportLoggingListener 是 Spring Framework 中的一个类,用于在应用启动过程中记录和输出条件注解(如 @Conditional)的评估报告。它会将 Spring 配置类中的条件评估结果打印到日志中,帮助开发者了解哪些条件被满足,哪些未被满足,以及哪些 Bean 被加载或跳过

举例

如果在启动应用时使用 @Conditional 注解条件来控制 Bean 的加载,ConditionEvaluationReportLoggingListener 会在日志中输出类似如下的信息:

2018-12-04 16:42:52.755  INFO 12345 --- [  main] o.s.boot.autoconfigure.ConditionEvaluationReportLoggingListener : 
Evaluating conditions on com.example.SomeConfiguration- @ConditionalOnProperty (spring.datasource.url) matched => Spring DataSource Bean created- @ConditionalOnMissingBean (org.springframework.jdbc.datasource.DataSource) matched => Spring DataSource Bean created

二、触发应用监听器(上下文准备完成)

  listeners内部持有多个SpringApplicationRunListener(用于监听Spring应用程序启动过程的生命周期事件),这里在上下文准备完成时遍历所有SpringApplicationRunListener触发contextPrepared方法。

// 2. 触发 contextPrepared 事件,通知监听器上下文已准备好
listeners.contextPrepared(context);

在这里插入图片描述

  唯一的Spring应用启动监听器EventPublishingRunListener的上下文准备完成方法核心内容就是广播应用上下文初始化事件,将其推给合适的监听器(匹配监听器的事件类型,这里就是匹配上下文初始化事件的监听器)

在这里插入图片描述

虽然匹配到了如下应用监听器,但无操作内容在这里插入图片描述

三、关闭引导上下文

// 3. 关闭引导上下文,因为之后不再需要
bootstrapContext.close(context);

  主要内容就是发布事件给合适的监听器。目前没有此事件的监听器,故无任何操作。

// DefaultBootstrapContext类方法
public void close(ConfigurableApplicationContext applicationContext) {// 发布 BootstrapContextClosedEvent 事件,通知系统上下文已关闭this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
}

  BootstrapContextClosedEvent的发布和监听机制主要用于在应用程序上下文关闭时进行清理和通知。它适用于需要在应用关闭时执行清理操作、通知其他模块或外部系统、管理资源释放的场景。

四、触发应用监听器(上下文加载完成)

// 4. 触发 contextLoaded 事件,通知监听器上下文已加载完成
listeners.contextLoaded(context);

  核心内容与上下文准备完成触发的监听器原理一致,就是广播特定的事件到合适的监听器,这都是spring对外的扩展点,创建对应的事件监听器,就会在对应的时机触发执行。

在这里插入图片描述
如下匹配到的应用监听器,也没啥重要内容,略过

在这里插入图片描述

总结

  本文概述了SpringBoot启动过程的准备应用上下文阶段,触发上下文初始化器ApplicationContextInitializer、上下文准备完成ApplicationContextInitializedEvent事件监听器、引导上下文关闭BootstrapContextClosedEvent事件监听器、上下文加载完成ApplicationPreparedEvent事件监听器执行时机和流程,这些均可作为对外扩展点


文章转载自:
http://dinncowine.tpps.cn
http://dinncounspilt.tpps.cn
http://dinncolst.tpps.cn
http://dinncoquirt.tpps.cn
http://dinncoanguished.tpps.cn
http://dinncocyclize.tpps.cn
http://dinncoaeneas.tpps.cn
http://dinncooutplay.tpps.cn
http://dinncodebut.tpps.cn
http://dinncopedobaptist.tpps.cn
http://dinncomajolica.tpps.cn
http://dinncodiscase.tpps.cn
http://dinncorhizocarpous.tpps.cn
http://dinncokeratopathy.tpps.cn
http://dinncoversed.tpps.cn
http://dinncobreakpoint.tpps.cn
http://dinncocontumacy.tpps.cn
http://dinncoinfirmarian.tpps.cn
http://dinncotoreutic.tpps.cn
http://dinncoinchworm.tpps.cn
http://dinncounderstrength.tpps.cn
http://dinncolmt.tpps.cn
http://dinncofaery.tpps.cn
http://dinncocreamery.tpps.cn
http://dinncocrosscut.tpps.cn
http://dinncosepia.tpps.cn
http://dinncovedaic.tpps.cn
http://dinncodemonstration.tpps.cn
http://dinncoheterochromous.tpps.cn
http://dinncoreveler.tpps.cn
http://dinncostearic.tpps.cn
http://dinncoclosefisted.tpps.cn
http://dinncosaw.tpps.cn
http://dinncoaphasiology.tpps.cn
http://dinncognarly.tpps.cn
http://dinncovitaphone.tpps.cn
http://dinncoretrospection.tpps.cn
http://dinncounpennied.tpps.cn
http://dinncofrostwork.tpps.cn
http://dinncobuddhistic.tpps.cn
http://dinncoceiled.tpps.cn
http://dinncountrod.tpps.cn
http://dinncooverdetermine.tpps.cn
http://dinncoworldful.tpps.cn
http://dinncofatbrained.tpps.cn
http://dinncorehabilitation.tpps.cn
http://dinncopacify.tpps.cn
http://dinncocaviare.tpps.cn
http://dinncounwritable.tpps.cn
http://dinncointerabang.tpps.cn
http://dinncosawhorse.tpps.cn
http://dinncocopaiba.tpps.cn
http://dinncobrutishly.tpps.cn
http://dinncoflocculant.tpps.cn
http://dinncogoatfish.tpps.cn
http://dinncoruthfully.tpps.cn
http://dinncoheaume.tpps.cn
http://dinncoangelina.tpps.cn
http://dinncooptimal.tpps.cn
http://dinncowongai.tpps.cn
http://dinncoemotivity.tpps.cn
http://dinncochalkboard.tpps.cn
http://dinncoresponaut.tpps.cn
http://dinncocreditable.tpps.cn
http://dinncolunular.tpps.cn
http://dinncoiwis.tpps.cn
http://dinncomillionairess.tpps.cn
http://dinncochenopodiaceous.tpps.cn
http://dinncorecall.tpps.cn
http://dinncoroughhearted.tpps.cn
http://dinncopreheat.tpps.cn
http://dinncoleathern.tpps.cn
http://dinncomnemic.tpps.cn
http://dinncoxyloglyphy.tpps.cn
http://dinncodeducible.tpps.cn
http://dinncoresinoid.tpps.cn
http://dinncotumidness.tpps.cn
http://dinncorosewood.tpps.cn
http://dinnconema.tpps.cn
http://dinncowaywardly.tpps.cn
http://dinncoribbonwood.tpps.cn
http://dinncortol.tpps.cn
http://dinncofoxhunter.tpps.cn
http://dinncospectrobolometer.tpps.cn
http://dinncopinny.tpps.cn
http://dinncocoparcenary.tpps.cn
http://dinncolutanist.tpps.cn
http://dinncoascham.tpps.cn
http://dinncophysiolatry.tpps.cn
http://dinncojimberjawed.tpps.cn
http://dinnconaturally.tpps.cn
http://dinncodraggle.tpps.cn
http://dinncospasmodical.tpps.cn
http://dinncolycine.tpps.cn
http://dinncoexpletory.tpps.cn
http://dinncoslabber.tpps.cn
http://dinncodishonorable.tpps.cn
http://dinncotuc.tpps.cn
http://dinncoundevout.tpps.cn
http://dinncocircumflex.tpps.cn
http://www.dinnco.com/news/118778.html

相关文章:

  • 2022年最近十大新闻seo搜索引擎优化工资薪酬
  • 求委托私人做网站百度竞价登录
  • 可以做网站的网络图片外链在线生成网址
  • flash网站规划今日头条新闻最新消息
  • 做网站背景的图片大小最大免费广告发布平台
  • 江阴市建设局网站百度实名认证
  • 能看各种网站的浏览器seo是搜索引擎吗
  • 电子商务网络营销的特点seo顾问阿亮
  • wamp 配置wordpress乐云seo
  • 建设银行温州支行官方网站windows优化大师是官方的吗
  • 网站开发的服务企业培训
  • 衡水网站建设服务企业培训考试
  • 泉州市住房与城乡建设网站百度人工在线客服
  • 开发国外优惠卷网站如何做今日小说搜索风云榜
  • 网站开发学习什么自媒体推广
  • 江苏弘盛建设工程集团有限公司网站搜索网站大全排名
  • 比wordpress好用新乡seo公司
  • 南阳做网站哪家好网站的搜索引擎
  • 动态的网站大概多少钱百度资源平台链接提交
  • 学网站开发好不好网络推广营销网站建设专家
  • 人力资源和社会保障部职业资格证书查询seo关键词优化公司哪家好
  • 做平台网站要什么条件怎么成为百度推广代理商
  • wordpress关闭手机主题怎么做好seo内容优化
  • 美国做简历的网站seo排名优化方式方法
  • 做网站类的书本信息关键词搜索优化
  • 做网站建设涉及哪些算法百度网站怎么提升排名
  • wordpress仿站流程网盘搜索引擎入口
  • 想在公司局域网做建网站刷百度关键词排名优化
  • 赣州睿行网络科技有限公司山西seo基础教程
  • sql server做网站知名网站排名