日拱一卒系列(如何定製springboot項目banner)

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了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章