1.引子
(oschina最近文章審覈很怪異,有時後可以看,有時候訪問受限制,小夥伴們可以在公衆號上看:地道程序員) springboot項目,在啓動的時候,官方有一個默認的banner,像下面這樣
那麼你有沒有想過,這個banner是如何實現的呢?如果在我們的項目中,假如說需要換成與項目相關的banner,該如何去換呢?
事實上非常簡單!今天這篇文章,除了分享替換官方的banner外,我還會帶着你一起通過源碼,看一看banner的加載過程。讓我們開始吧!
2.案例
2.1.替換banner案例
2.1.1.初步體驗
要替換springboot項目官方的banner,其實非常簡單。首先我們在項目的resource目錄下,創建一個banner.txt文件,如下圖
有了banner.txt文件,然後增加文件內容,文件內容如何增加呢?這裏我們先打開一個網址:http://patorjk.com/software/taag/,通過這個網站,幫助我們生成想要的banner內容,比如我輸入:hdedu,輸出:
.__ .___ .___
| |__ __| _/____ __| _/_ __
| | \ / __ |/ __ \ / __ | | \
| Y \/ /_/ \ ___// /_/ | | /
|___| /\____ |\___ >____ |____/
\/ \/ \/ \/
我們將輸出內容,拷貝到banner.txt文件中,如下
最後啓動項目,我們會發現,banner內容已經替換成我們想要的了,漂亮!
2.1.2.高級體驗
初步體驗中,通過創建banner.txt文件,非常簡單就實現了替換官方的banner,但是效果稍微有點醜,能不能美化一下呢?比如說
-
換個顏色
-
增加多一些描述信息
答案是:都可以,在banner.txt文件中,增加一些控制內容
${AnsiColor.BLUE}
.__ .___ .___
| |__ __| _/____ __| _/_ __
| | \ / __ |/ __ \ / __ | | \
| Y \/ /_/ \ ___// /_/ | | /
|___| /\____ |\___ >____ |____/
\/ \/ \/ \/
${spring-boot.version}
${spring-boot.formatted-version}
你看,通過${xxx}的形式,我們可以對banner做一些個性化的定製。其中AnsiColor是一個枚舉類,用於指定banner的顏色。具體你可以看一下它的源代碼。
2.2.banner加載過程分析
體驗了替換springboot項目的banner以後,不知道你是不是會好奇,它是怎麼加載實現的呢?
我當初學習springboot框架的時候,就是帶着這樣的好奇,然後去翻看源代碼,我們常說源碼之下無祕密,不是沒有道理的。來吧,我帶着你一起看一下!
要看springboot框架的源碼,應該從啓動類開始
/**
* 啓動類
*
* @author ThinkPad
* @version 1.0
* @date 2021/7/23 20:18
*/
@SpringBootApplication
public class SpringBootEduBannerApplication {
/**
* main方法
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(SpringBootEduBannerApplication.class, args);
}
}
springboot項目的啓動類,關注兩個內容
-
@SpringBootApplication註解:自動裝配、組件掃描
-
SpringApplication.run方法:初始化項目流程入口
關於springboot項目的啓動初始化流程,內容比較多,還是比較複雜的,改天我專門通過一篇文章來分享,今天我們僅僅關注banner相關的內容。點擊進入SpringApplication類的run方法中,一直跟蹤到方法
public ConfigurableApplicationContext run(String... args) {
......省略其它代碼......
try{
......省略其它代碼......
// 打印banner內容
Banner printedBanner = this.printBanner(environment);
// 創建spring IOC容器
context = this.createApplicationContext();
......省略其它代碼......
}catch(Throwable var10){
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
......省略其它代碼......
}
進一步跟蹤到printBanner方法中
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Mode.OFF) {
return null;
} else {
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader((ClassLoader)null);
// banner處理類
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner);
// 輸入banner內容
return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
}
跟進到SpringApplicationBannerPrinter類的print方法中
Banner print(Environment environment, Class<?> sourceClass, Log logger) {
// 獲取banner內容,這行代碼是關鍵
Banner banner = this.getBanner(environment);
try {
logger.info(this.createStringFromBanner(banner, environment, sourceClass));
} catch (UnsupportedEncodingException var6) {
logger.warn("Failed to create String for banner", var6);
}
return new SpringApplicationBannerPrinter.PrintedBanner(banner, sourceClass);
}
跟進getBanner方法
private Banner getBanner(Environment environment) {
SpringApplicationBannerPrinter.Banners banners = new SpringApplicationBannerPrinter.Banners();
// 獲取圖片banner內容,支持圖片文件banner.jpg/png/gif格式
banners.addIfNotNull(this.getImageBanner(environment));
// 獲取文本banner內容,對應案例中banner.txt文件
banners.addIfNotNull(this.getTextBanner(environment));
if (banners.hasAtLeastOneBanner()) {
return banners;
} else {
return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;
}
}
跟進getTextBanner方法
private Banner getTextBanner(Environment environment) {
// 加載類路徑下的banner.txt文件內容
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 var5) {
;
}
return null;
}
一路跟着源代碼到這裏,相信你可以理解爲什麼我們在resource目錄下(類路徑下),增加banner.txt文件後,即可以替換官方的banner了。