SpringBoot自定义Banner
SpringBoot
项目启动的时候会输出一个Spring
的图标。
思考🤔
- 它是在哪个环节的时候输出的呢?
- 是否可以自定义图标呢?
源码分析
通常我们SpringBoot项目是通过
SpringBoot.run(Appcation.class)
启动的。
run()
public ConfigurableApplicationContext run(String... args) {
try {
// 关键是这两行
// 第一行是初始化环境信息也就是会将我们配置文件中的内容,或者是System.getProperties()中的信息进行封装
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 通过环节信息来构建Banner并输出对于的内容
Banner printedBanner = printBanner(environment);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
return context;
}
printBanner()
private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
private Banner printBanner(ConfigurableEnvironment environment) {
// 判断横幅的模式 是否为禁用 ,默认是输出到控制台
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(null);
// 创建一个SpringApplicationBannerPrinter对象
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
// 判断横幅模式是否为输出到日志
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
// 默认情况会走到这里
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
Banner.Mode
enum Mode {
/**
* 禁用横幅的打印
*/
OFF,
/**
* 将横幅输出到System.out
*/
CONSOLE,
/**
* 将横幅输出到日志文件中
*/
LOG
}
SpringApplicationBannerPrinter.print()
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
// 根据环节信息创建一个Banner
Banner banner = getBanner(environment);
// 实际输出Banner的地方
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
getBanner()
// private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private Banner getBanner(Environment environment) {
Banners banners = new Banners();
// 判断是否存在image的横幅
banners.addIfNotNull(getImageBanner(environment));
// 判断是否存在文本的横幅
banners.addIfNotNull(getTextBanner(environment));
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
// 这里如果在配置中没有得到Banner的话,则会使用SpringBoot默认的
return DEFAULT_BANNER;
}
// 从当前环境中取出spring.banner.image.location
// 判断这个路径下是否存在文件,存在则创建一个ImageBanner
// 不存在这尝试读取类路径下的banner.gif, banner.jpg", banner.png
// 都不存在则返回一个NULL
private Banner getImageBanner(Environment environment) {
String location = environment.getProperty("spring.banner.image.location");
if (StringUtils.hasLength(location)) {
Resource resource = this.resourceLoader.getResource(location);
return resource.exists() ? new ImageBanner(resource) : null;
}
for (String ext : IMAGE_EXTENSION) {
Resource resource = this.resourceLoader.getResource("banner." + ext);
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
// 从当前环境中取出spring.banner.location配置的值 默认是banner.txt 可以自定义。通过这个路径来创建一个ResourceBanner
private Banner getTextBanner(Environment environment) {
String location = environment.getProperty("spring.banner.location", "banner.txt");
Resource resource = this.resourceLoader.getResource(location);
try {
if (resource.exists() && !resource.getURL().toExternalForm().contains("liquibase-core")) {
return new ResourceBanner(resource);
}
}
catch (IOException ex) {
// Ignore
}
return null;
}
SpringBootBanner
class SpringBootBanner implements Banner {
private static final String[] BANNER = { "", " . ____ _ __ _ _",
" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
" =========|_|==============|___/=/_/_/_/" };
private static final String SPRING_BOOT = " :: Spring Boot :: ";
private static final int STRAP_LINE_SIZE = 42;
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
for (String line : BANNER) {
printStream.println(line);
}
String version = SpringBootVersion.getVersion();
version = (version != null) ? " (v" + version + ")" : "";
StringBuilder padding = new StringBuilder();
while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
padding.append(" ");
}
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
AnsiStyle.FAINT, version));
printStream.println();
}
}
这里可以看见
BANNER
是一个字符串数组,实际打印的也就是这个数组的值。也就是我们的Spring
图标以及一些版本信息。
小结
从源码中分析得出,在不配置
spring.banner.location
与spring.banner.image.location
的情况下,SpringBoot默认会使用SpringBootBanner
来进行输出。输出的则是Spring
的图标。当我们想自定义图标的话,则可以使用
spring.banner.location
来指定一个横幅文件的位置,或者直接在类路径下创建一个banner.txt
,并把横幅的内容写入到里面。
实践
创建一个banner.txt
,并写入程序员万岁!
;
输出效果
感觉很low😂。如何让他变的跟Spring那个图标一样好看呢。
Spring Boot自定义启动Banner在线生成工具
替换banner.tet
内容,效果。
补充
纯字体的网站
-
(推荐)https://www.bootschool.net/ascii
-
http://patorjk.com/software/taag/
-
http://www.network-science.de/ascii/
图片风
-
(推荐)https://www.bootschool.net/ascii-art/animals
-
https://www.degraeve.com/img2txt.php
内置变量
- spring-boot.version:SpringBoot的版本号
- spring-boot.formatted-version:带v的版本号
总结
https://www.bootschool.net/ascii-art/animals
- https://www.degraeve.com/img2txt.php
内置变量
- spring-boot.version:SpringBoot的版本号
- spring-boot.formatted-version:带v的版本号
[外链图片转存中…(img-kzLyUrAu-1705820973870)]
总结
直接在类路径下创建
banner.txt
来替换SpringBoot
默认的输出最为方便,想要美化的话,可以通过一些工具来进行生成。