Spring Boot 源码学习系列
上篇博文,Huazie 带大家了解了完整的 Banner 信息打印流程。相信大家都跃跃一试了,那么本篇就以这些基础的知识,来自定义 Banner 信息打印。
注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。
在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:
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 |
【Spring Boot 源码学习】Banner 信息打印流程 |
通过 SpringApplicationBannerPrinter##getTextBanner 方法的源码了解,我们现在可以进行如下的操作:
当没有配置 spring.banner.location 属性,Spring Boot 默认就会加载资源根目录的 banner.txt 文件,如果存在该资源文件,则会使用 ResourceBanner 打印 Banner 信息。
下面我们在新建的 demo 项目的资源根目录添加名为 banner.txt 的资源文件,如下图所示:
然后,直接运行我们的 DemoApplication 入口类,可见如下运行截图:
现在我们把上面的 banner.txt 移到资源根目录新建的 banner 目录里,并更名为 mybanner.txt,如下图所示:
接着,在 application.properties 中配置如下:
# Banner 资源文件路径 spring.banner.location=classpath:banner/mybanner.txt
然后,还是直接运行我们的 DemoApplication 入口类,可见如下运行截图:
查看 ResourceBanner 的源码,我们可以看到如下的代码:
这里就不得不提 PropertyResolver,它是 Spring 框架中的一个组件,主要用于解析各种属性源的属性值。它能够处理多种类型的底层源,包括properties 文件、yaml 文件,甚至是一些 nosql 数据库【因为这些数据源同样采用 key-value 形式存储数据】。
查看 PropertyResolver 的 API 中,我可以看到它定义了一系列读取、解析和判断是否包含指定属性的方法。此外,它还支持以 ${propertyName:defaultValue} 格式的属性占位符,替换为实际的值的功能,这在动态配置中非常有用。
接下来,我们在 application.properties 中配置如下:
然后,我们在 banner.txt 中可以添加如下属性占位符:
最后,运行我们的 DemoApplication 入口类,可见如下运行截图:
通过 SpringApplicationBannerPrinter##getImageBanner 方法的源码了解,我们现在可以进行如下的操作:
当没有配置 spring.banner.image.location 属性,Spring Boot 默认就会加载资源根目录的 banner.gif 或 banner.jpg 或 banner.png 等文件,如果存在其中某个资源文件,则会使用 ImageBanner 打印 Banner 信息。
下面我们在新建的 demo 项目的资源根目录添加名为 banner.gif 的资源文件,如下图所示:
然后,同样运行我们的 DemoApplication 入口类,可见如下运行截图:
换成另外两个 banner.jpg 或 banner.png 也是能够加载的,如下:
默认 Banner 图像资源的加载逻辑:
- 存在 banner.gif,则只加载 banner.gif;
- 不存在 banner.gif,存在 banner.jpg,则只加载 banner.jpg
- 不存在 banner.gif,也不存在 banner.jpg,则加载 banner.png
现在我们把上面的 banner.png 移到资源根目录新建的 banner 目录里,并更名为 mybanner.png,如下图所示:
接着,在 application.properties 中配置如下:
# Banner 图像资源文件路径 spring.banner.image.location=classpath:banner/mybanner.png
然后,我们运行 DemoApplication 入口类,可见如下运行截图:
查看 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 :设置图片的的像素模式,有如下两个枚举值:
下面我们就来添加这些属性,来看看效果:
spring.banner.image.width=50
运行 DemoApplication 入口类,可见如下运行截图:
spring.banner.image.height=20
依旧运行 DemoApplication 入口类,可见如下运行截图:
spring.banner.image.margin=5
同样运行 DemoApplication 入口类,可见如下运行截图:
spring.banner.image.invert=true
继续运行 DemoApplication 入口类,可见如下运行截图:
spring.banner.image.bitdepth=8
然后运行 DemoApplication 入口类,可见如下运行截图:
我们发现上述好像设置了该属性,展示出来的图像并没有啥差异,事实上在也的确如此,可能我们的图像比较简单。
spring.banner.image.pixelmode=block
运行 DemoApplication 入口类,可见如下运行截图:
Banners 是 SpringApplicationBannerPrinter 的私有静态内部类,它也实现了 Banner 接口,添加多个不同的 Banner 实现。在 SpringApplicationBannerPrinter##getBanner 方法中就能看到,新建 Banners 实例,并往其中添加了 ImageBanner 和 ResourceBanner 。
按照 Banners 的打印顺序,先添加进去的,先打印。
我们看看 ImageBanner 和 ResourceBanner 同时生效的场景:
运行 DemoApplication 入口类,可见如下运行截图:
通过阅读 SpringApplicationBannerPrinter 的源码,我们知道如果 Banners 中没有 ResourceBanner 或者 ImageBanner 中的任何一个,就会判断自身的 fallbackBanner 变量是否存在,存在则直接返回。而该 fallbackBanner 变量实际上是 SpringApplication 中的 banner 变量。
而我们查看 SpringApplication 的源码,可以看到如下方法:
下面就需要我们来自定义 Banner 接口的实现:
/** * 自定义 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,如下:
@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 的其他内容,敬请期待!!!