【Spring Boot 源码学习】Banner 信息打印流程

news2024/11/18 2:23:44

Spring Boot 源码学习系列

在这里插入图片描述

Banner 信息打印流程

  • 引言
  • 往期内容
  • 主要内容
    • 1. printBanner 方法
    • 2. 关闭 Banner 信息打印
    • 3. SpringApplicationBannerPrinter 类
      • 3.1 LOG 模式打印
        • 3.1.1 getBanner 方法
          • 3.1.1.1 新建 Banners
          • 3.1.1.2 添加 ImageBanner
          • 3.1.1.3 添加 ResourceBanner
          • 3.1.1.4 确认并返回 Banner 实现
        • 3.1.2 以日志模式打印
      • 3.2 CONSOLE 模式打印
        • 3.2.1 getBanner 方法
        • 3.2.2 以控制台模式打印
  • 总结

引言

上篇博文,Huazie 带大家初步了解了 SpringApplication 的实例化过程。在介绍 SpringApplication 的核心构造函数的第一个参数 ResourceLoader 时,简单提及了它用于 Spring Boot 在启动时打印对应的 Banner 信息。这里就引申出了本篇将要介绍的 Banner 信息打印流程。

在这里插入图片描述

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解
【Spring Boot 源码学习】@Conditional 条件注解
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
【Spring Boot 源码学习】RedisAutoConfiguration 详解
【Spring Boot 源码学习】JedisConnectionConfiguration 详解
【Spring Boot 源码学习】初识 SpringApplication

主要内容

1. printBanner 方法

话不多说,我们先来看 SpringApplication 中,有关打印 banner 信息的源码:

在这里插入图片描述

上述代码其实是 SpringApplication 实例化之后,在其 public ConfigurableApplicationContext run(String... args) 方法中被调用的,以下为源码截图,暂不展开介绍,下面重点介绍 printBanner 方法的执行流程。

在这里插入图片描述

2. 关闭 Banner 信息打印

我们进入 printBanner 方法,先看到了如下判断:

if (this.bannerMode == Banner.Mode.OFF) {
	return null;
}

如果 bannerMode 是关闭模式,则直接返回 null,即不打印 banner 信息。

那我们如何设置 bannerMode 为关闭模式呢?

SpringApplication 中,提供了如下的 setXXX 方法进行设置:

public void setBannerMode(Banner.Mode bannerMode) {
	this.bannerMode = bannerMode;
}

那么我们就可以在启动入口类中,这样来编写:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(DemoApplication.class);
        springApplication.setBannerMode(Banner.Mode.OFF);
        springApplication.run(args);
    }
}

将上述 setBannerMode 调用注释掉,运行 DemoApplication 类,可见如下截图:

在这里插入图片描述
setBannerMode 调用注释放开,继续运行 DemoApplication 类,可见如下截图:

在这里插入图片描述

3. SpringApplicationBannerPrinter 类

我们继续往下看源码:

ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(null);
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);

第一行代码是获取资源加载类 ResourceLoader ,如果 SpringApplication 中的 resourceLoader 变量不为 null,则使用该变量对应的类作为资源加载类,否则新建一个 DefaultResourceLoader 作为默认的资源加载类;

第二行代码是实例化 Banner 打印类 SpringApplicationBannerPrinter ,它的构造函数分别是:

  • ResourceLoader resourceLoader : 资源加载类
  • Banner fallbackBannerbanner 信息打印接口类在这里插入图片描述

最后根据 bannerMode 的值不同,有下面两种 banner 信息打印模式:

3.1 LOG 模式打印

LOG 模式打印,可见如下:

bannerPrinter.print(environment, this.mainApplicationClass, logger);

继续查看 SpringApplicationBannerPrinter 类的 print 方法,如下图所示:

在这里插入图片描述

3.1.1 getBanner 方法

首先,这里先调用了 getBanner 方法,它用于获取一个 Banner 接口,该接口对应实际要打印的 Banner 信息的实现类。

我们查看其相关源码,如下图所示:

在这里插入图片描述

3.1.1.1 新建 Banners

BannersSpringApplicationBannerPrinter 的私有静态内部类,它实现了 Banner 接口,可以添加多个不同的 Banner 实现,也就是它组合了多个不同的 Banner 实现,其 printBanner 方法就是将内部的不同的 Banner 实现按添加顺序依次调用它们自己的 printBanner 方法进行打印。

Banners 的相关源码,如下图所示:

在这里插入图片描述

新建了 Banners 的对象 banners 之后, 我们继续往下看:

3.1.1.2 添加 ImageBanner
banners.addIfNotNull(getImageBanner(environment));

这里往 banners 中添加了一个 ImageBanner ,该类也是 Banner 接口的一个实现,用于打印从图像资源生成的 ASCII艺术【它是一种使用标准 ASCII 字符集创建的视觉艺术形式】。当然如果 getImageBanner 方法返回 null,那么 bannersaddIfNotNull 也不会处理。

我们继续看 getImageBanner 方法,如下图所示:

在这里插入图片描述

下面我们来仔细分析一下上述逻辑:

  • 首先,这里从环境配置中获取BANNER_IMAGE_LOCATION_PROPERTY 属性值【即 spring.banner.image.location 属性对应的值】;
  • 接着,判断上述 Banner 图像位置属性是否存在???
  • 如果 Banner 图像位置属性存在,则通过资源加载类 resourceLoader 获取对应路径的资源对象 resource
    • 如果资源存在,则直接返回一个 ImageBanner 的实例对象,构造参数传入上述获取的资源对象 resource
    • 如果资源不存在,则直接返回 null
  • 如果 Banner 图像位置属性不存在,则依次通过资源加载类 resourceLoader 获取 banner.gifbanner.jpgbanner.png 的图像资源 resource,如果先匹配到其中一个,则直接返回一个 ImageBanner 的实例对象,构造参数传入上述获取的图像资源 resource
  • 最后,上述都没有资源存在,则返回 null
3.1.1.3 添加 ResourceBanner
banners.addIfNotNull(getTextBanner(environment));

这里往 banners 中添加了一个 ResourceBanner,该类同样也是 Banner 接口的一个实现,用于从源文本资源中打印 Banner 信息。当然如果 getTextBanner 方法返回 null,那么 bannersaddIfNotNull 也不会处理。

我们继续看 getTextBanner 方法,如下图所示:

在这里插入图片描述

相比 getImageBanner 方法,getTextBanner 方法的逻辑就比较简单:

  • 首先,这里依旧是从环境配置中获取 BANNER_LOCATION_PROPERTY 属性对应的资源位置值【即 spring.banner.location 属性对应的值】;如果未获取到,则默认的资源位置就是 DEFAULT_BANNER_LOCATION【即 banner.txt】;
  • 接着,通过资源加载类 resourceLoader 获取指定的位置资源对象 resource
  • 然后,检查资源 resource 是否存在且其URL不包含"liquibase-core"字符串?
    • 如果满足条件,则创建一个 ResourceBanner 对象并返回。
    • 如果在尝试访问资源时发生 IOException 异常,将在 catch 语句块中忽略该异常。
  • 最后,如果没有找到符合条件的资源或发生异常,最终将返回 null
3.1.1.4 确认并返回 Banner 实现
if (banners.hasAtLeastOneBanner()) {
	return banners;
}
if (this.fallbackBanner != null) {
	return this.fallbackBanner;
}
return DEFAULT_BANNER;

如果上述的 banners 中至少存在一个 Banner 实现,则直接返回 banners 对象。

反之,如果实例化 SpringApplicationBannerPrinter 时,构造函数传入的 fallbackBanner 不为空,则直接返回 fallbackBanner 作为 最终的 Banner 实现。

如果上述都不符合要求,则返回默认的 Banner 实现 DEFAULT_BANNER 【即 SpringBootBanner】。

private static final Banner DEFAULT_BANNER = new SpringBootBanner();

SpringBootBanner 其实就是我们启动 Spring Boot 打印出来的信息,如下所示:

在这里插入图片描述

3.1.2 以日志模式打印
try {
	logger.info(createStringFromBanner(banner, environment, sourceClass));
}
catch (UnsupportedEncodingException ex) {
	logger.warn("Failed to create String for banner", ex);
}

上述 3.1.1 中的截图就是利用日志对象,打印 INFO 级别的 Banner 信息,最终会被输出到日志文件中。

Banner 的具体信息,可见 createStringFromBanner 方法,我们继续进入查看:

在这里插入图片描述

这里逻辑并不复杂,总结如下:

  • 首先,创建一个字节数组输出流 baos,用于接收要打印的 Banner 信息;
  • 接着,调用 3.1.1.4 中获取的 Banner 实现的 printBanner 方法,将要打印的 Banner 信息输出到 baos 中【这里具体看不同的 Banner 实现】;
  • 然后,从环境配置中获取 Banner 字符集属性值【即 spring.banner.charset 属性对应的值】;如果无法获取,则默认是 UTF-8
  • 最后,将字节数组输出流转换为指定字符集的字符串,并返回

3.2 CONSOLE 模式打印

默认情况下就是 CONSOLE 模式打印,可见如下:

bannerPrinter.print(environment, this.mainApplicationClass, System.out)

继续查看 SpringApplicationBannerPrinter 类的 另一个 print 方法,如下图所示:

在这里插入图片描述

3.2.1 getBanner 方法

详见 3.1.1 ,这里不再赘述。

3.2.2 以控制台模式打印

由于上面是将 System.out 传入到 PrintStream 中,所以最终是将 Banner 信息直接输出到控制台,可见如下截图:

在这里插入图片描述

总结

本篇 Huazie 带大家通读了 Banner 信息打印的源码,相信如果上面的内容都看下来的话,完全熟悉 Banner 信息打印流程不再是个问题。有了这些基础的知识,我们就可以来自定义 Banner 信息打印,敬请期待下篇博文!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1226530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flume的安装部署及常见问题解决

1.安装地址 (1) Flume官网地址:http://flume.apache.org/ (2)文档查看地址:http://flume.apache.org/FlumeUserGuide.html (3)下载地址:http://archive.apache.org/dist…

RVC从入门到......

RVC变声器官方教程:10分钟克隆你的声音!一键训练,低配显卡用户福音!_哔哩哔哩_bilibili配音:AI逍遥散人(已授权)关注UP主并私信"RVC"(三个字母)自动获取一键训…

PS 颜色取样器标尺工具 基本使用讲解

上文 PS 吸管工具基本使用方法 我们讲完了 吸管工具 那么 我们继续 打开ps先 接着 我们选择这个 颜色取样器工具 选择之后 我们鼠标在图像上随便点一下 就会出现一个标记 然后 我们可以点多几个地方 边上的信息面板就会输出 点1 和 点2 甚至 多个 点3 点4 的 颜色 RGB代码 …

Python 如何实现备忘录设计模式?什么是备忘录设计模式?Python 备忘录设计模式示例代码

什么是备忘录(Memento)设计模式? 备忘录(Memento)设计模式是一种行为型设计模式,用于捕获一个对象的内部状态,并在对象之外保存这个状态,以便在需要时恢复对象到先前的状态。这种模…

[qemu逃逸] DefconQuals2018-EC3

前言 一道简单的套壳堆题.原本题目环境为 ubu16, 我这里使用的是 ubu18 设备逆向 qemu-system-x86_64 只开了 Canary 和 NX 保护. 比较简单, 主要逻辑在 mmio_write 里面, 其实现了一个菜单堆, 具有增删改的功能: 但是在释放堆块时并没有置空, 所以这里存在 UAF. 而程序还直…

三、程序员指南:数据平面开发套件

定时器库 定时器库为DPDK执行单元提供了定时器服务,以便异步执行回调函数。该库的特点包括: 定时器可以是周期性的(多次触发)或单次的(一次性触发)。定时器可以从一个核加载并在另一个核上执行。这必须在…

IntelliJ IDEA 2023 v2023.2.5

IntelliJ IDEA 2023是一款功能强大的集成开发环境(IDE),为开发人员提供了许多特色功能,以下是其特色介绍: 新增语言支持:IntelliJ IDEA 2023新增对多种编程语言的支持,包括Kotlin、TypeScript、…

介绍交换空间概念以及如何设置交换空间

文章目录 什么交换空间新增交换空间 什么交换空间 交换空间(Swap space)是计算机内存的一种补充,位于硬盘驱动器上。当物理内存不足时,系统会将不活跃的页面移到交换空间中。 交换空间可以帮助系统在以下情况下运行&#xff1a…

mysql 实现去重

个人网站 首发于公众号小肖学数据分析 1、试题描述 数据表user_test如下,请你查询所有投递用户user_id并且进行去重展示,查询结果和返回顺序如下 查询结果和返回顺序如下所示 解题思路: (1) 对user_id列直接去重: &#xff…

Kotlin学习(一)

Kotlin学习&#xff08;一&#xff09; 1.使用IDEA构建Kotlin项目 新建工程即可 我这里选择的Build System是IntelliJ&#xff0c;虽然我没用过但是这是Kotlin基础学习应该不会用到其他依赖 2.Hello World package com.simonfun main(args:Array<String>){println(&q…

Go 语言中切片的使用和理解

切片与数组类似&#xff0c;但更强大和灵活。与数组一样&#xff0c;切片也用于在单个变量中存储相同类型的多个值。然而&#xff0c;与数组不同的是&#xff0c;切片的长度可以根据需要增长和缩小。在 Go 中&#xff0c;有几种创建切片的方法&#xff1a; 使用[]datatype{val…

使用 C 语言快速排序将字符串按照 ASCII 码升序排列

示例代码&#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h>static Comp(const void *a, const void *b) {char *pa (char *)a;char *pb (char *)b;return strcmp(a, b); }int main(void) {char strs[3][10] { "bd", &q…

C++ Qt 学习(十):Qt 其他技巧

1. 带参数启动外部进程 QProcess 用于启动外部进程int QProcess::execute(const QString &program, const QStringList &arguments);QObject *parent; ... QString program "./path/to/Qt/examples/widgets/analogclock"; QStringList arguments; argument…

卷积、卷积图像操作和卷积神经网络

好多内容直接看书确实很难坚持&#xff0c;就比如这个卷积&#xff0c;书上的一大堆公式和图表直接把人劝退&#xff0c;我觉得一般的学习流程应该是自顶向下&#xff0c;先整体后局部&#xff0c;先把握大概再推敲细节的&#xff0c;上来就事无巨细地展示对初学者来说很痛苦。…

泉盛UV-K5/K6全功能中文固件

https://github.com/wu58430/uv-k5-firmware-chinese/releases 主要功能&#xff1a; 中文菜单 许多来自 OneOfEleven 的模块&#xff1a; AM 修复&#xff0c;显著提高接收质量长按按钮执行 F 操作的功能复制快速扫描菜单中的频道名称编辑频道名称 频率显示选项扫描列表分配…

文本转语音

免费工具 音视频转译 通义听悟 | https://tingwu.aliyun.com/u/wg57n33kml5nkr3p 音色迁移 speechify | https://speechify.com/voice-cloning/ 视频生成 lalamu | http://lalamu.studio/demo/ 画质增强 topazlabs video AI | https://www.topazlabs.com 付费工具 rask | htt…

重生奇迹mu转职任务详解

重生奇迹mu神骑士怎么转 神骑士是一种转职类型&#xff0c;需要你的角色达到一定等级以及完成相应任务方可转职。以下是神骑士转职的具体步骤&#xff1a; 1.等级要求&#xff1a;首先&#xff0c;你的角色需要达到150级才能进行神骑士转职任务。 2.神骑士转职任务&#xff…

hyperledger fabric2.4测试网络添加组织数量

!!!修改内容比较繁琐,预期未来提供模板修改 修改初始配置文件,初始添加3个组织 organizations文件夹 /cryptogen文件夹下创建文件crypto-config-org3.yaml,内容如下: PeerOrgs:# ---------------------------------------------------------------------------# Org3# ----…

获取每个部门中当前员工薪水最高的相关信息

个人网站 首发于公众号小肖学数据分析 描述 有一个员工表dept_emp简况如下: 有一个薪水表salaries简况如下: 获取每个部门中当前员工薪水最高的相关信息&#xff0c;给出dept_no, emp_no以及其对应的salary&#xff0c;按照部门编号dept_no升序排列&#xff0c;以上例子输出…

ESP32 MicroPython 蜂鸣器及传感器的使用⑦

ESP32 MicroPython 蜂鸣器及传感器的使用⑦ 1、蜂鸣器奏乐2、实验目的3、实验内容5、实验结果6、小车传感器应用7、实验目的8、实验内容9、参考代码10、实验结果 1、蜂鸣器奏乐 我们小车底板配置有蜂鸣器&#xff0c;下面我们来学习如何去利用蜂鸣器演奏乐曲 2、实验目的 学…