【Spring Boot 源码学习】自定义 Banner 信息打印

引言

上篇博文,Huazie 带大家了解了完整的 Banner 信息打印流程。相信大家都跃跃一试了,那么本篇就以这些基础的知识,来自定义 Banner 信息打印。

主要内容

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

1. ResourceBanner 打印

通过 SpringApplicationBannerPrinter##getTextBanner 方法的源码了解,我们现在可以进行如下的操作:

1.1 添加默认的 banner.txt 资源文件

当没有配置 spring.banner.location 属性,Spring Boot 默认就会加载资源根目录的 banner.txt 文件,如果存在该资源文件,则会使用 ResourceBanner 打印 Banner 信息。

下面我们在新建的 demo 项目的资源根目录添加名为 banner.txt 的资源文件,如下图所示:

然后,直接运行我们的 DemoApplication 入口类,可见如下运行截图:

1.2 指定任意路径的资源文件

现在我们把上面的 banner.txt 移到资源根目录新建的 banner 目录里,并更名为 mybanner.txt,如下图所示:

接着,在 application.properties 中配置如下:

1
2
# Banner 资源文件路径
spring.banner.location=classpath:banner/mybanner.txt

然后,还是直接运行我们的 DemoApplication 入口类,可见如下运行截图:

1.3 添加自定义的信息

查看 ResourceBanner 的源码,我们可以看到如下的代码:



这里就不得不提 PropertyResolver,它是 Spring 框架中的一个组件,主要用于解析各种属性源的属性值。它能够处理多种类型的底层源,包括properties 文件、yaml 文件,甚至是一些 nosql 数据库【因为这些数据源同样采用 key-value 形式存储数据】。

查看 PropertyResolverAPI 中,我可以看到它定义了一系列读取、解析和判断是否包含指定属性的方法。此外,它还支持以 ${propertyName:defaultValue} 格式的属性占位符,替换为实际的值的功能,这在动态配置中非常有用。

接下来,我们在 application.properties 中配置如下:

然后,我们在 banner.txt 中可以添加如下属性占位符:

最后,运行我们的 DemoApplication 入口类,可见如下运行截图:

2. ImageBanner 打印

通过 SpringApplicationBannerPrinter##getImageBanner 方法的源码了解,我们现在可以进行如下的操作:

2.1 添加默认的图像资源文件

当没有配置 spring.banner.image.location 属性,Spring Boot 默认就会加载资源根目录的 banner.gifbanner.jpgbanner.png 等文件,如果存在其中某个资源文件,则会使用 ImageBanner 打印 Banner 信息。

下面我们在新建的 demo 项目的资源根目录添加名为 banner.gif 的资源文件,如下图所示:

然后,同样运行我们的 DemoApplication 入口类,可见如下运行截图:

换成另外两个 banner.jpgbanner.png 也是能够加载的,如下:

默认 Banner 图像资源的加载逻辑:

  • 存在 banner.gif,则只加载 banner.gif
  • 不存在 banner.gif,存在 banner.jpg,则只加载 banner.jpg
  • 不存在 banner.gif,也不存在 banner.jpg,则加载 banner.png

2.2 指定任意路径的图像资源文件

现在我们把上面的 banner.png 移到资源根目录新建的 banner 目录里,并更名为 mybanner.png,如下图所示:

接着,在 application.properties 中配置如下:

1
2
# Banner 图像资源文件路径
spring.banner.image.location=classpath:banner/mybanner.png

然后,我们运行 DemoApplication 入口类,可见如下运行截图:

2.3 添加自定义的图像显示信息

查看 ImageBanner 的源码,我们可以看到如下的代码:



从上述源码,我们看到 ImageBanner 里面可以自定义一些图像的显示属性,比如:

  • spring.banner.image.width :设置 banner 图像的宽度,默认为 76 像素

  • spring.banner.image.height :设置 banner 图像的高度,默认按照宽度计算缩放比例,重新计算新图像的高度。

  • spring.banner.image.margin :设置 banner 图像的外边距,默认为 2 像素

  • spring.banner.image.invert :设置是否反转图片的颜色。如果设置为 true,则颜色会被反转

  • spring.banner.image.bitdepth :设置图片的位深度,默认 4 位深度,还支持 8 位深度。位深度决定了图片的颜色精度,例如8位深度表示每个像素有256种颜色,不过大多数情况下,对于 Banner 图像输出到控制台,看起来基本没啥区别。

  • spring.banner.image.pixelmode :设置图片的的像素模式,有如下两个枚举值:

    • TEXT :文本模式,适用于需要清晰、简洁的图像效果的情况。
    • BLOCK :块模式,适用于需要强调图像的某些部分或突出显示特定区域的情况。

下面我们就来添加这些属性,来看看效果:

2.3.1 添加 Banner 图像宽度属性

1
spring.banner.image.width=50

运行 DemoApplication 入口类,可见如下运行截图:

2.3.2 添加 Banner 图像高度属性

1
spring.banner.image.height=20

依旧运行 DemoApplication 入口类,可见如下运行截图:

2.3.3 添加 Banner 图像外边距属性

1
spring.banner.image.margin=5

同样运行 DemoApplication 入口类,可见如下运行截图:

2.3.4 添加 Banner 图像是否反转图片颜色的属性

1
spring.banner.image.invert=true

继续运行 DemoApplication 入口类,可见如下运行截图:

2.3.5 添加 Banner 图像位深度的属性

1
spring.banner.image.bitdepth=8

然后运行 DemoApplication 入口类,可见如下运行截图:


我们发现上述好像设置了该属性,展示出来的图像并没有啥差异,事实上也的确如此,可能我们的图像比较简单。

2.3.6 添加 Banner 图像像素模式的属性

1
spring.banner.image.pixelmode=block

运行 DemoApplication 入口类,可见如下运行截图:

3. Banners 打印

BannersSpringApplicationBannerPrinter 的私有静态内部类,它也实现了 Banner 接口,添加多个不同的 Banner 实现。在 SpringApplicationBannerPrinter##getBanner 方法中就能看到,新建 Banners 实例,并往其中添加了 ImageBannerResourceBanner

按照 Banners 的打印顺序,先添加进去的,先打印。


我们看看 ImageBannerResourceBanner 同时生效的场景:

运行 DemoApplication 入口类,可见如下运行截图:

4. 自定义 Banner 接口实现

通过阅读 SpringApplicationBannerPrinter 的源码,我们知道如果 Banners 中没有 ResourceBanner 或者 ImageBanner 中的任何一个,就会判断自身的 fallbackBanner 变量是否存在,存在则直接返回。而该 fallbackBanner 变量实际上是 SpringApplication 中的 banner 变量。



而我们查看 SpringApplication 的源码,可以看到如下方法:

下面就需要我们来自定义 Banner 接口的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 自定义 Banner 接口实现
*
* @author huazie
* @version 2.0.0
* @since 2.0.0
*/
public class CustomBanner implements Banner {

@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
String author = environment.getProperty("author");

out.println(" _ _ _ ");
out.println("| | | |_ _ __ _ ___(_) ___ ");
out.println("| |_| | | | |/ _` |_ / |/ _ \\");
out.println("| _ | |_| | (_| |/ /| | __/");
out.println("|_| |_|\\__,_|\\__,_/___|_|\\___|");
out.println(" ");
out.println(" 作者: " + author);
out.println();
}
}

接下来,修改入口类 DemoApplication,如下:

1
2
3
4
5
6
7
8
9
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.setBanner(new CustomBanner());
springApplication.run(args);
}
}

最后运行 DemoApplication 入口类,可见如下运行截图:

总结

本篇 Huazie 带大家自定义 Banner 信息打印,再次加深了对 Banner 信息打印流程的理解。当然,这只是 Spring Boot 启动过程中的一个小插曲,后续的博文我们将继续深入讲解 SpringApplication 的其他内容,敬请期待!!!