日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot源码解析(十一)自定义banner

發(fā)布時間:2024/3/13 javascript 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot源码解析(十一)自定义banner 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上篇文章結(jié)束了prepareEnvironment方法的分析,本篇繼續(xù)SpringApplication的run方法往下走,看一個比較簡單的點——banner打印

所謂banner就是SpringBoot應(yīng)用啟動的時候打印在控制臺的一個logo

涉及到的代碼為下面這行printBanner

在這之前,先簡單說下上面的這行configureIgnoreBeanInfo

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {if (System.getProperty("spring.beaninfo.ignore") == null) {Boolean ignore = (Boolean)environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);System.setProperty("spring.beaninfo.ignore", ignore.toString());}}

它將環(huán)境配置中的spring.beaninfo.ignore屬性設(shè)置到系統(tǒng)變量中,如果沒有配置,就默認為true

這個屬性主要和內(nèi)省機制有關(guān),這里不詳細展開,很多工具類比如BeanUtils底層都依賴了內(nèi)省,spring.beaninfo.ignore設(shè)置為true,會忽略自定義的BeanInfo

至于為什么SpringBoot把這個屬性默認設(shè)置為true,我個人的理解是很多底層的機制都依賴了內(nèi)省,而自定義BeanInfo很可能干擾使用了內(nèi)省機制的相關(guān)功能,所以SpringBoot不推薦使用,實際工作中也極少會做BeanInfo層面的定制

接下來進入正題,點開printBanner方法

private Banner printBanner(ConfigurableEnvironment environment) {if (this.bannerMode == Mode.OFF) {return null;} else {ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(this.getClassLoader());SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner);return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out);}}

bannerMode是banner打印的模式,取值有三個

public static enum Mode {OFF,CONSOLE,LOG; }

OFF就是不打印banner,CONSOLE是打印到標(biāo)準(zhǔn)輸出流,會輸出到控制臺,LOG就是打印到日志文件

bannerMode在SpringApplication對象的構(gòu)造函數(shù)里初始化為CONSOLE

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {......this.bannerMode = Mode.CONSOLE;...... }

所以默認就是只打印到控制臺的,但是一般我們項目都會集成一些日志框架,這些框架也可以把標(biāo)準(zhǔn)輸出流的內(nèi)容重定向到日志文件中

如果沒有設(shè)置為關(guān)閉,就進入printBanner方法的else分支

...... ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(this.getClassLoader()); SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner); return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out); ......

第一行定義了一個ResourceLoader,由于SpringApplication對象的resourceLoader并沒有初始化,所以new了一個DefaultResourceLoader,這個東西我們已經(jīng)見了很多次了

接下來新建了一個SpringApplicationBannerPrinter,入?yún)⑹莿倓?chuàng)建的DefaultResourceLoader和SpringApplication對象的banner屬性,這個屬性同樣沒有初始化,所以此時也是null

SpringApplicationBannerPrinter內(nèi)部封裝了將banner打印到不同渠道的方法,先看下它的成員變量

class SpringApplicationBannerPrinter {static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";static final String DEFAULT_BANNER_LOCATION = "banner.txt";static final String[] IMAGE_EXTENSION = new String[]{"gif", "jpg", "png"};private static final Banner DEFAULT_BANNER = new SpringBootBanner();private final ResourceLoader resourceLoader;private final Banner fallbackBanner;

banner可以是圖片形式,也可以是文本形式,可供我們自定義配置,前兩個成員變量就是自定義文本banner和圖片banner的默認配置名,后續(xù)尋找banner的時候,先看有沒有自定義,如果沒有,再找默認的banner文件
第三個變量為默認的文本banner文件,即classpath下的banner.txt
第四個變量為默認的圖片banner的后綴名,圖片banner可以支持多種格式,即會到classpath下找圖片banner.gif / jpg / png

最后根據(jù)bannerMode是LOG還是CONSOLE,調(diào)用SpringApplicationBannerPrinter對象不同的print方法,這兩個print方法內(nèi)部實現(xiàn)大致相同,只不過打印的目的地分別為log文件以及標(biāo)準(zhǔn)輸出流System.out,我們這里就按照默認情況,看下打印到System.out的代碼

public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {Banner banner = this.getBanner(environment);banner.printBanner(environment, sourceClass, out);return new SpringApplicationBannerPrinter.PrintedBanner(banner, sourceClass);}

第一行先獲取Banner對象

private Banner getBanner(Environment environment) {SpringApplicationBannerPrinter.Banners banners = new SpringApplicationBannerPrinter.Banners();banners.addIfNotNull(this.getImageBanner(environment));banners.addIfNotNull(this.getTextBanner(environment));if (banners.hasAtLeastOneBanner()) {return banners;} else {return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;}}

Banner對象就是對banner內(nèi)容的封裝,文本類型的banner會封裝到ResourceBanner中,圖片類型則封裝到ImageBanner,而SpringBootBanner是默認的banner,我們下面會見到

先嘗試獲取圖片類型的banner

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;} else {String[] var3 = IMAGE_EXTENSION;int var4 = var3.length;for(int var5 = 0; var5 < var4; ++var5) {String ext = var3[var5];Resource resource = this.resourceLoader.getResource("banner." + ext);if (resource.exists()) {return new ImageBanner(resource);}}return null;}}

到environment中查找配置spring.banner.image.location(SpringBoot中很多地方都是這樣,雖然上面定義了靜態(tài)變量,但是下面很多代碼并沒有引用),如果沒有指定,就到classpath下看有沒有默認的banner圖片,也就是上面提到的在classpath下找圖片banner.gif / jpg / png

接下來再找txt類型的banner

private Banner getTextBanner(Environment environment) {String location = environment.getProperty("spring.banner.location", "banner.txt");Resource resource = this.resourceLoader.getResource(location);return resource.exists() ? new ResourceBanner(resource) : null;}

先到environment看是否有配置spring.banner.location,如果沒有,再默認找classpath下的banner.txt

如果圖片類型和文本類型的banner都沒有找到,就取fallbackBanner

return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;

這個fallbackBanner傳進來的是SpringApplication對象的banner屬性,它并沒有初始化,所以是null的,也就是說最終的fallbackBanner賦值為DEFAULT_BANNER,它是SpringApplicationBannerPrinter的靜態(tài)變量,初始化為SpringBootBanner

class SpringApplicationBannerPrinter {......private static final Banner DEFAULT_BANNER = new SpringBootBanner();......

看下這個SpringBootBanner 的實現(xiàn)

class SpringBootBanner implements Banner {private static final String[] BANNER = new String[]{"", " . ____ _ __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /", " =========|_|==============|___/=/_/_/_/"};private static final String SPRING_BOOT = " :: Spring Boot :: ";private static final int STRAP_LINE_SIZE = 42;SpringBootBanner() {}

第一行String類型的數(shù)組,其實就是我們文章開頭看到的SpringBoot默認的banner,它是以字符串的形式寫死在代碼里的

獲取到banner后,調(diào)用它的print方法,最終通過System.out.println()將banner內(nèi)容寫到控制臺

public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {try {String banner = StreamUtils.copyToString(this.resource.getInputStream(), (Charset)environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8));PropertyResolver resolver;for(Iterator var5 = this.getPropertyResolvers(environment, sourceClass).iterator(); var5.hasNext(); banner = resolver.resolvePlaceholders(banner)) {resolver = (PropertyResolver)var5.next();}out.println(banner);} catch (Exception var7) {logger.warn("Banner not printable: " + this.resource + " (" + var7.getClass() + ": '" + var7.getMessage() + "')", var7);}}

很多公司都會在SpringBoot基礎(chǔ)上做一層封裝,然后加上自己公司的banner,這里附上一個自定義banner的網(wǎng)站

自定義banner
(https://patorjk.com/software/taag/#p=display&f=Doom&t=mybanner)

比如取名為MyBanner,然后將內(nèi)同拷貝到classpath下的banner.txt

啟動項目,默認banner已經(jīng)被替換了

總結(jié)

以上是生活随笔為你收集整理的SpringBoot源码解析(十一)自定义banner的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。