我是陳皮,一個在網際網路 Coding 的 ITer,微信搜尋「陳皮的JavaLib」第一時間閱讀最新文章,回覆【資料】,即可獲得我精心整理的技術資料,電子書籍,一線大廠面試資料和優秀簡歷模板。
前言
我們在啟動 Spring Boot 專案時,預設會在控制檯列印 Spring
logo 和版本等資訊,如下:
這就是 Spring Boot 的 Banner 列印功能,其實我們可以自定義列印的 banner ,也可以禁用和啟用列印 banner 功能。在真實專案中,我們一般不會去自定義 banner 圖案,它其實就是專案啟動時列印圖案或者文字而已,沒實際意義。推薦在自己個人專案玩玩這個彩蛋即可,順便簡單瞭解下它內部實現原理。
比如,自定義一個 banner 之後,專案啟動控制檯列印如下所示:
實現原理
Spring Boot 有一個介面 org.springframework.boot.Banner
專門實現這個操作。要想自定義列印 banner ,只要自定義一個類實現這個介面,重寫 printBanner
方法進行列印即可。Springboot 專案啟動時,會建立我們的實現類物件,並呼叫物件的 printBanner
方法。
package org.springframework.boot;
import java.io.PrintStream;
import org.springframework.core.env.Environment;
/**
* Interface class for writing a banner programmatically.
* 用於以程式設計方式編寫 banner 的介面類
* @since 1.2.0
*/
@FunctionalInterface
public interface Banner {
/**
* Print the banner to the specified print stream.
* 將 banner 列印到指定的列印流。
* @param environment the spring environment
* @param sourceClass the source class for the application
* @param out the output print stream
*/
void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);
// 用於配置Banner的的列舉值
enum Mode {
// 關閉 banner 列印
OFF,
// 列印 banner 到 控制檯
CONSOLE,
// 列印 banner 到日誌檔案
LOG
}
}
預設 Banner 實現類
Springboot 已經有幾個自帶的 Banner 實現類,Springboot 啟動時會根據條件選擇不同的 Banner 實現類進行列印 banner 資訊。主要是 ImageBanner
,ResourceBanner
,SpringBootBanner
這三個實現類。
- 專案啟動時,會判斷是否某些條件成立(專案中是否存在 banner 檔案),成立則建立
ImageBanner
和ResourceBanner
類物件,並且使用它們來列印 banner。 - 如果不成立檢查是否存在我們自定義的 Banner 實現類
fallbackBanner
,如果存在則使用它來列印 banner 圖案。 - 否則,則使用預設的
SpringBootBanner
實現類來列印 banner,也就是我們經常看到Spring
圖案。
// 獲取可用的 Banner 實現類
private Banner getBanner(Environment environment) {
Banners banners = new Banners();
banners.addIfNotNull(getImageBanner(environment));
banners.addIfNotNull(getTextBanner(environment));
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
// SpringBootBanner 實現類
return DEFAULT_BANNER;
}
ImageBanner
org.springframework.boot.ImageBanner
類是專門載入和列印圖片 banner 的。它檢查配置檔案 application.proeprties
是否有配置的 spring.banner.image.location
變數的值,這個值可用來指定要載入的圖片,如果存在則構建 ImageBanner 物件。如果沒有配置變數,則還會檢查 Classpath
下是否存在以 banner
開頭,以 .gif
,.jpg
,.png
結尾的圖片檔案,如果有也會構建 ImageBanner 物件。
class SpringApplicationBannerPrinter {
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
// 獲取 ImageBanner 物件
private Banner getImageBanner(Environment environment) {
// 載入 spring.banner.image.location 指定的檔案,檔案存在則構建 ImageBanner 物件
String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
if (StringUtils.hasLength(location)) {
Resource resource = this.resourceLoader.getResource(location);
return resource.exists() ? new ImageBanner(resource) : null;
}
// 查詢 banner.gif,banner.jpg,banner.png 檔案
for (String ext : IMAGE_EXTENSION) {
Resource resource = this.resourceLoader.getResource("banner." + ext);
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
}
ResourceBanner
org.springframework.boot.ResourceBanner
類是專門載入和列印字元 banner 的。它檢查配置檔案 application.proeprties
是否有配置的 spring.banner.location
變數的值,這個值可用來指定要載入的檔案,如果存在則構建 ResourceBanner 物件。如果沒有配置變數,則還會檢查資源路徑下是否存在 banner.txt
檔案,如果存在也會構建 ResourceBanner 物件。
class SpringApplicationBannerPrinter {
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
// 獲取 ResourceBanner 物件
private Banner getTextBanner(Environment environment) {
String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);
Resource resource = this.resourceLoader.getResource(location);
if (resource.exists()) {
return new ResourceBanner(resource);
}
return null;
}
}
如果想要自定義 banner,我們一般在專案的 resources 資源目錄下建立 banner.txt
檔案,然後在裡面填入我們想要的列印的文字內容即可。例如我在 banner.txt 檔案中填充了 Chen Pi
內容,然後啟動專案。
SpringBootBanner
如果專案沒有設定以上兩種自定義的 banner(ImageBanner 和 ResourceBanner),則預設情況下,會使用 SpringBootBanner 實現類列印 banner ,也就是我們啟動 Springboot 專案時在控制檯看到的列印 Spring
圖案。原始碼如下:
package org.springframework.boot;
import java.io.PrintStream;
import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiStyle;
import org.springframework.core.env.Environment;
/**
* Default Banner implementation which writes the 'Spring' banner.
*/
class SpringBootBanner implements Banner {
// 這個就是我們啟動 Springboot 專案時在控制檯看到的圖案
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 類
前面說我們可以實現 Banner 類,重寫列印方法,實現自定義 banner 列印功能。
package com.chenpi;
import java.io.PrintStream;
import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;
/**
* @Description 自定義 Banner 實現類
* @Author Mr.nobody
* @Date 2021/6/4
* @Version 1.0
*/
public class MyBanner implements Banner {
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
String banner = " .__ .__ \n"
+ " ____ | |__ ____ ____ ______ |__|\n"
+ "_/ ___\\| | \\_/ __ \\ / \\ \\____ \\| |\n"
+ "\\ \\___| Y \\ ___/| | \\ | |_> > |\n"
+ " \\___ >___| /\\___ >___| / | __/|__|\n"
+ " \\/ \\/ \\/ \\/ |__| ";
out.println(banner);
}
}
建立自定義的 Banner 實現類物件,設定到 SpringApplication
類物件的 banner 屬性,最終這個屬性的值會會被賦值到 SpringApplicationBannerPrinter
物件的 fallbackBanner
屬性中,感興趣的可以啟動 debug 跟蹤下。
package com.chenpi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootBannerApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class);
// 設定自定義 Banner
springApplication.setBanner(new MyBanner());
// 啟動 SpringBoot
springApplication.run(args);
}
}
Banner 樣式控制
文章一開始的佛祖圖形,你會發現是翠綠色的。其實 Springboot 支援我們修改 banner 的顏色,字型斜體,粗體等樣式。SpringBoot 為我們提供了三個列舉類來設定這些樣式。
- AnsiColor:設定字元的前景色;參考
org.springframework.boot.ansi.AnsiColor
列舉類。 - AnsiBackground:設定字元的背景色;參考
org.springframework.boot.ansi.AnsiBackground
列舉類。 - AnsiStyle:設定字元的加粗、斜體、下劃線等等;參考
org.springframework.boot.ansi.AnsiStyle
列舉類。
而且,在 banner.txt 檔案中還可以引用一些全域性變數,例如:
- ${spring-boot.version}:Spring Boot 版本號;
- ${spring-boot.formatted-version}:格式化後的 Spring Boot 版本號資訊。
- ${application.version}:MANIFEST.MF 檔案中的版本號;
- ${application.formatted-version}:格式化後的 MANIFEST.MF 檔案中的版本號資訊;
不僅如此,還可以引用我們在配置檔案 application.properties
中定義的變數,例如在配置檔案中定義瞭如下變數:
application.auth=chenpi
定義的 banner.txt 檔案內容如下:
${AnsiColor.BRIGHT_GREEN}
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不當機 永無BUG //
////////////////////////////////////////////////////////////////////
${AnsiColor.BRIGHT_CYAN}
Application Version: ${application.version}${application.formatted-version}
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
By -- ${application.auth}
啟動專案,會在控制檯列印的 banner 如下:
Banner 模式
在 Banner 介面中有定義一個列舉類,這個列舉定義了配置 Banner 的可能列舉值,如下:
@FunctionalInterface
public interface Banner {
// 用於配置Banner的的列舉值
enum Mode {
// 關閉 banner 列印
OFF,
// 列印 banner 到 控制檯
CONSOLE,
// 列印 banner 到日誌檔案
LOG
}
}
所以我們可以選擇關閉 banner,banner 列印到控制檯還是日誌檔案,如下:
package com.chenpi;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootBannerApplication {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class);
// 關閉 banner
springApplication.setBannerMode(Mode.OFF);
// 啟動 SpringBoot
springApplication.run(args);
}
}
也可以配置檔案中設定此值,如下
spring.main.banner-mode=off
如果啟動類跟配置檔案中都配置了對banner開關的設定,配置檔案中設定的banner開關會優先於啟動類中設定的開關。
banner 圖生成工具
可能有人會問佛祖的圖案怎麼編輯出來的,其實網上有很多工具可以根據我們輸入的內容或者圖片,個性化製作ASCII字元和圖案,推薦網址如下:
- 定製化 ASCII 字元:http://network-science.de/ascii/
- 定製化 ASCII 圖片:https://www.degraeve.com/img2txt.php