最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot打印Banner的實(shí)現(xiàn)示例

 更新時(shí)間:2025年01月08日 09:48:19   作者:冬天vs不冷  
本文主要介紹了SpringBoot啟動(dòng)Banner的實(shí)現(xiàn)原理和打印流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在前文中,我們深入解析了SpringBoot啟動(dòng)時(shí)應(yīng)用環(huán)境的準(zhǔn)備過(guò)程。接下來(lái)將深入介紹啟動(dòng)Banner打印的具體實(shí)現(xiàn)及流程。

SpringBoot版本2.7.18SpringApplication的run方法的執(zhí)行邏輯如下,本文將詳細(xì)介紹第5小節(jié):打印啟動(dòng)Banner

// SpringApplication類(lèi)方法
public ConfigurableApplicationContext run(String... args) {
    // 記錄應(yīng)用啟動(dòng)的開(kāi)始時(shí)間
    long startTime = System.nanoTime();

    // 1.創(chuàng)建引導(dǎo)上下文,用于管理應(yīng)用啟動(dòng)時(shí)的依賴(lài)和資源
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;

    // 配置無(wú)頭模式屬性,以支持在無(wú)圖形環(huán)境下運(yùn)行
    // 將系統(tǒng)屬性 java.awt.headless 設(shè)置為 true
    configureHeadlessProperty();

    // 2.獲取Spring應(yīng)用啟動(dòng)監(jiān)聽(tīng)器,用于在應(yīng)用啟動(dòng)的各個(gè)階段執(zhí)行自定義邏輯
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 啟動(dòng)開(kāi)始方法(發(fā)布開(kāi)始事件、通知應(yīng)用監(jiān)聽(tīng)器ApplicationListener)
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    try {
        // 3.解析應(yīng)用參數(shù)
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        // 4.準(zhǔn)備應(yīng)用環(huán)境,包括讀取配置文件和設(shè)置環(huán)境變量
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

        // 配置是否忽略 BeanInfo,以加快啟動(dòng)速度
        configureIgnoreBeanInfo(environment);

        // 5.打印啟動(dòng)Banner
        Banner printedBanner = printBanner(environment);

        // 6.創(chuàng)建應(yīng)用程序上下文
        context = createApplicationContext();
        
        // 設(shè)置應(yīng)用啟動(dòng)的上下文,用于監(jiān)控和管理啟動(dòng)過(guò)程
        context.setApplicationStartup(this.applicationStartup);

        // 7.準(zhǔn)備應(yīng)用上下文,包括加載配置、添加 Bean 等
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

        // 8.刷新上下文,完成 Bean 的加載和依賴(lài)注入
        refreshContext(context);

        // 9.刷新后的一些操作,如事件發(fā)布等
        afterRefresh(context, applicationArguments);

        // 計(jì)算啟動(dòng)應(yīng)用程序的時(shí)間,并記錄日志
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }

        // 10.通知監(jiān)聽(tīng)器應(yīng)用啟動(dòng)完成
        listeners.started(context, timeTakenToStartup);

        // 11.調(diào)用應(yīng)用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便執(zhí)行自定義的啟動(dòng)邏輯
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        // 12.處理啟動(dòng)過(guò)程中發(fā)生的異常,并通知監(jiān)聽(tīng)器
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 13.計(jì)算應(yīng)用啟動(dòng)完成至準(zhǔn)備就緒的時(shí)間,并通知監(jiān)聽(tīng)器
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
        // 處理準(zhǔn)備就緒過(guò)程中發(fā)生的異常
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }

    // 返回已啟動(dòng)并準(zhǔn)備就緒的應(yīng)用上下文
    return context;
}

一、入口

// 5.打印啟動(dòng)Banner
Banner printedBanner = printBanner(environment);

// 打印啟動(dòng) Banner 的方法,根據(jù)配置的 Banner 模式選擇打印方式
private Banner printBanner(ConfigurableEnvironment environment) {
    // 如果 Banner 模式被設(shè)置為 OFF,則不打印 Banner,直接返回 null
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }

    // 確定資源加載器。如果當(dāng)前實(shí)例的 resourceLoader 不為空,則使用它;否則創(chuàng)建一個(gè)默認(rèn)的資源加載器
    ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
            : new DefaultResourceLoader(null);

    // 創(chuàng)建 Banner 打印器,負(fù)責(zé)加載和打印 Banner
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);

    // 根據(jù) Banner 模式?jīng)Q定打印到日志還是控制臺(tái)
    if (this.bannerMode == Mode.LOG) {
        // 如果 Banner 模式為 LOG,則將 Banner 打印到日志中
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }

    // 默認(rèn)情況下(CONSOLE 模式),將 Banner 打印到標(biāo)準(zhǔn)輸出(控制臺(tái))
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

二、Banner接口類(lèi)

// 一個(gè)用于以編程方式輸出 Banner 的接口類(lèi)
@FunctionalInterface
public interface Banner {
	// 將 Banner 輸出到指定的打印流
	void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);

	// 用于配置 Banner 的模式枚舉
	enum Mode {
		// 禁用 Banner 的打印
		OFF,
		// 將 Banner 輸出到 System.out
		CONSOLE,
		// 將 Banner 輸出到日志文件
		LOG
	}
}

1、打印Banner開(kāi)關(guān)

  • 默認(rèn)情況是打印到控制臺(tái)

在這里插入圖片描述

  • 可以通過(guò)properties或yml設(shè)置關(guān)閉打印Banner
spring.main.banner-mode=off

上一節(jié)有講spring.main開(kāi)頭的屬性會(huì)綁定到SpringApplication對(duì)象上,這樣就可以通過(guò)配置文件的屬性來(lái)決定Banner的打印模式。

三、打印Banner過(guò)程

1、console和log模式

  • console控制臺(tái)模式,默認(rèn)設(shè)置
// SpringApplicationBannerPrinter類(lèi)方法
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    // 根據(jù)提供的環(huán)境信息獲取橫幅。
    Banner banner = getBanner(environment);
    
    // 將橫幅打印到指定的輸出流中。
    banner.printBanner(environment, sourceClass, out);
    
    // 返回一個(gè) PrintedBanner 對(duì)象,包含打印的橫幅和源類(lèi)信息。
    return new PrintedBanner(banner, sourceClass);
}
  • log日志文件模式,通過(guò)在配置文件中設(shè)置spring.main.banner-mode=log,可以將應(yīng)用啟動(dòng)Banner輸出到日志文件中
// SpringApplicationBannerPrinter類(lèi)方法
Banner print(Environment environment, Class<?> sourceClass, Log logger) {
	// 根據(jù)提供的環(huán)境信息獲取橫幅。
	Banner banner = getBanner(environment);
	try {
		logger.info(createStringFromBanner(banner, environment, sourceClass));
	}
	catch (UnsupportedEncodingException ex) {
		logger.warn("Failed to create String for banner", ex);
	}
	// 返回一個(gè) PrintedBanner 對(duì)象,包含打印的橫幅和源類(lèi)信息。
	return new PrintedBanner(banner, sourceClass);
}
  • log模式就是獲取打印流內(nèi)容轉(zhuǎn)換為字符串,然后由log日志打印罷了

在這里插入圖片描述

兩種方式都會(huì)返回一個(gè)PrintedBanner對(duì)象,主要是為以后在應(yīng)用上下文中注冊(cè)為Bean或供其他組件使用做準(zhǔn)備。

2、四種Banner對(duì)象

  • 圖片和文本橫幅組合的Banners
  • 備用Banner
  • 默認(rèn)Banner
// SpringApplicationBannerPrinter類(lèi)方法

// 默認(rèn)Banner
private static final Banner DEFAULT_BANNER = new SpringBootBanner();

// 根據(jù)當(dāng)前環(huán)境獲取適當(dāng)?shù)臋M幅(Banner)
private Banner getBanner(Environment environment) {
    // 創(chuàng)建一個(gè) Banners 對(duì)象,用于存儲(chǔ)圖片和文本橫幅
    Banners banners = new Banners();
    // 嘗試獲取圖片橫幅,并將其添加到 Banners 中(如果非空)
    banners.addIfNotNull(getImageBanner(environment));
    // 嘗試獲取文本橫幅,并將其添加到 Banners 中(如果非空)
    banners.addIfNotNull(getTextBanner(environment));
    // 如果至少包含一個(gè)橫幅,則返回組合的 Banners 對(duì)象
    if (banners.hasAtLeastOneBanner()) {
        return banners;
    }
    
    // 如果沒(méi)有任何橫幅但存在備用橫幅,則返回備用橫幅
    if (this.fallbackBanner != null) {
        return this.fallbackBanner;
    }
    
    // 如果沒(méi)有任何橫幅,則返回默認(rèn)橫幅
    // Banner DEFAULT_BANNER = new SpringBootBanner();
    return DEFAULT_BANNER;
}
  • Banners對(duì)象內(nèi)部持有多個(gè)Banner實(shí)現(xiàn)類(lèi),遍歷調(diào)用Banner的printBanner方法

在這里插入圖片描述

2.1、圖片Banner

  • 嘗試根據(jù)環(huán)境信息獲取圖片橫幅(Image Banner)
  • 環(huán)境變量spring.banner.image.location用于指定圖片路徑;如果未設(shè)置,則默認(rèn)加載路徑為banner.gifbanner.jpgbanner.png(按順序查找)。
private Banner getImageBanner(Environment environment) {
    // 從環(huán)境變量中獲取橫幅圖片的路徑
    // String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
    String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
    
    // 如果路徑不為空,嘗試加載對(duì)應(yīng)的資源
    if (StringUtils.hasLength(location)) {
        Resource resource = this.resourceLoader.getResource(location);
        // 如果資源存在,返回對(duì)應(yīng)的 ImageBanner 對(duì)象
        return resource.exists() ? new ImageBanner(resource) : null;
    }

    // 如果未指定路徑,嘗試加載默認(rèn)圖片橫幅文件
    // String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
    for (String ext : IMAGE_EXTENSION) {
        Resource resource = this.resourceLoader.getResource("banner." + ext);
        // 如果找到存在的文件資源,返回對(duì)應(yīng)的 ImageBanner 對(duì)象
        if (resource.exists()) {
            return new ImageBanner(resource);
        }
    }
    // 如果沒(méi)有找到任何圖片橫幅資源,返回 null
    return null;
}

控制臺(tái)效果

在這里插入圖片描述

2.2、文字Banner

  • 嘗試根據(jù)環(huán)境信息獲取文本橫幅(Text Banner)
  • 環(huán)境變量spring.banner.location用于指定文本路徑;如果未設(shè)置,則默認(rèn)加載路徑為banner.txt。
private Banner getTextBanner(Environment environment) {
    // 獲取橫幅的路徑,優(yōu)先使用環(huán)境變量中的配置,如果沒(méi)有配置則使用默認(rèn)路徑
    // String BANNER_LOCATION_PROPERTY = "spring.banner.location";
    // String DEFAULT_BANNER_LOCATION = "banner.txt";
    String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);

    // 使用 ResourceLoader 加載指定路徑的資源
    Resource resource = this.resourceLoader.getResource(location);

    try {
        // 檢查資源是否存在,且路徑中不包含 "liquibase-core"(防止加載到不相關(guān)的資源)
        if (resource.exists() && !resource.getURL().toExternalForm().contains("liquibase-core")) {
            // 如果資源有效,返回對(duì)應(yīng)的 ResourceBanner 對(duì)象
            return new ResourceBanner(resource);
        }
    } catch (IOException ex) {
        // 忽略異常,可能是資源加載時(shí)出錯(cuò)或路徑無(wú)效
        // 在這里不拋出異常,而是返回 null,表示沒(méi)有有效的橫幅資源
    }
    // 如果資源無(wú)效或發(fā)生異常,返回 null
    return null;
}

控制臺(tái)效果

在這里插入圖片描述

2.2、備用Banner

SpringApplicationBannerPrinter對(duì)象的備用Banner屬性fallbackBanner是由SpringApplication對(duì)象的私有屬性banner傳遞而來(lái)的。

在這里插入圖片描述

  • 可以在SpringBoot啟動(dòng)類(lèi)中通過(guò)調(diào)用SpringApplicationsetBanner方法直接設(shè)置自定義的Banner對(duì)象
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        // 設(shè)置全局備用橫幅
        app.setBanner((environment, sourceClass, out) -> {
            out.println("===== 全局備用橫幅 =====");
            out.println(" 默認(rèn)橫幅已啟用 ");
            out.println("=====================");
        });
        app.run(args);
    }
}

控制臺(tái)效果

在這里插入圖片描述

2.3、默認(rèn)Banner

如果未設(shè)置自定義文字圖片Banner或備用Banner,SpringBoot將使用默認(rèn)的啟動(dòng)橫幅(SpringBootBanner)作為顯示內(nèi)容。

// 默認(rèn)的 Banner 實(shí)現(xiàn),用于打印 "Spring" 的啟動(dòng)橫幅,和版本信息
class SpringBootBanner implements Banner {

    // 預(yù)定義的 ASCII 藝術(shù)橫幅,每行為一個(gè)數(shù)組元素
	private static final String[] BANNER = { 
		"", 
		"  .   ____          _            __ _ _",
		" /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
		"( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
		" \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", 
		"  '  |____| .__|_| |_|_| |_\\__, | / / / /",
		" =========|_|==============|___/=/_/_/_/" 
	};

	// 固定的 Spring Boot 標(biāo)識(shí)符,用于橫幅輸出
	private static final String SPRING_BOOT = " :: Spring Boot :: ";

	// 橫幅固定寬度,用于計(jì)算 padding 的空格數(shù)
	private static final int STRAP_LINE_SIZE = 42;

	/**
	 * 輸出橫幅到指定的 PrintStream(如控制臺(tái)或日志)。
	 */
	@Override
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
		// 遍歷并打印每一行 ASCII 藝術(shù)橫幅
		for (String line : BANNER) {
			printStream.println(line);
		}
		// 獲取 Spring Boot 的版本信息
		String version = SpringBootVersion.getVersion();
		// 如果版本信息不為空,則格式化為 "(vX.X.X)"
		version = (version != null) ? " (v" + version + ")" : "";
		
		// 構(gòu)造 padding 空格,使橫幅版本號(hào)對(duì)齊
		StringBuilder padding = new StringBuilder();
		while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
			padding.append(" ");
		}

		// 打印 Spring Boot 標(biāo)識(shí)符和版本信息,使用 ANSI 輸出樣式
		printStream.println(AnsiOutput.toString(
			AnsiColor.GREEN,       // 綠色輸出 Spring Boot 標(biāo)識(shí)符
			SPRING_BOOT, 
			AnsiColor.DEFAULT,     // 恢復(fù)默認(rèn)顏色
			padding.toString(),    // 填充的空格
			AnsiStyle.FAINT,       // 微弱樣式(淡化顯示版本信息)
			version                // 版本號(hào)
		));
		// 添加空行用于分隔橫幅和其他輸出
		printStream.println();
	}
}

控制臺(tái)效果

在這里插入圖片描述

總結(jié)

本文全面解析了SpringBoot啟動(dòng)橫幅的實(shí)現(xiàn)原理、打印流程及自定義方法,介紹了文本橫幅(默認(rèn)路徑為banner.txt,可通過(guò)spring.banner.location配置)、圖片橫幅(默認(rèn)路徑為banner.gif、banner.jpgbanner.png,可通過(guò)spring.banner.image.location配置)、備用橫幅和默認(rèn)橫幅的使用,幫助開(kāi)發(fā)者靈活運(yùn)用橫幅機(jī)制提升項(xiàng)目啟動(dòng)體驗(yàn)。

到此這篇關(guān)于SpringBoot打印Banner的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot打印Banner內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot中redis的緩存穿透問(wèn)題實(shí)現(xiàn)

    springboot中redis的緩存穿透問(wèn)題實(shí)現(xiàn)

    這篇文章主要介紹了springboot中redis的緩存穿透問(wèn)題實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 詳解eclipse項(xiàng)目中.classpath文件的使用

    詳解eclipse項(xiàng)目中.classpath文件的使用

    這篇文章主要介紹了詳解eclipse項(xiàng)目中.classpath文件的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Java基于Servlet和JSP實(shí)現(xiàn)登錄功能

    Java基于Servlet和JSP實(shí)現(xiàn)登錄功能

    在 Web 開(kāi)發(fā)中,用戶登錄功能是非常常見(jiàn)的模塊之一,本文將通過(guò)使用 Java Servlet 和 JSP 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的用戶登錄功能,展示如何創(chuàng)建登錄頁(yè)面、處理用戶登錄請(qǐng)求,并使用數(shù)據(jù)庫(kù)驗(yàn)證用戶信息,需要的朋友可以參考下
    2024-11-11
  • Mybatis使用concat函數(shù)問(wèn)題

    Mybatis使用concat函數(shù)問(wèn)題

    這篇文章主要介紹了Mybatis使用concat函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Spring MVC獲取HTTP請(qǐng)求頭的兩種方式小結(jié)

    Spring MVC獲取HTTP請(qǐng)求頭的兩種方式小結(jié)

    這篇文章主要介紹了Spring MVC獲取HTTP請(qǐng)求頭的兩種方式小結(jié),幫助大家更好的理解和使用Spring MVC,感興趣的朋友可以了解下
    2021-01-01
  • Java之String類(lèi)型的編碼方式轉(zhuǎn)換

    Java之String類(lèi)型的編碼方式轉(zhuǎn)換

    這篇文章主要介紹了Java之String類(lèi)型的編碼方式轉(zhuǎn)換,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • JAVA中實(shí)現(xiàn)原生的 socket 通信機(jī)制原理

    JAVA中實(shí)現(xiàn)原生的 socket 通信機(jī)制原理

    本篇文章主要介紹了JAVA中實(shí)現(xiàn)原生的 socket 通信機(jī)制原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • Java之jdbc連接mysql數(shù)據(jù)庫(kù)的方法步驟詳解

    Java之jdbc連接mysql數(shù)據(jù)庫(kù)的方法步驟詳解

    這篇文章主要介紹了Java之jdbc連接mysql數(shù)據(jù)庫(kù)的方法步驟詳解,JCBC技術(shù)是java開(kāi)發(fā)必備的只是,jdbc連接mysql數(shù)據(jù)庫(kù),這是一個(gè)比較簡(jiǎn)單的方法,有興趣的可以了解一下
    2020-07-07
  • 詳談Java中的事件監(jiān)聽(tīng)機(jī)制

    詳談Java中的事件監(jiān)聽(tīng)機(jī)制

    下面小編就為大家?guī)?lái)一篇詳談Java中的事件監(jiān)聽(tīng)機(jī)制。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • java的main方法中調(diào)用spring的service方式

    java的main方法中調(diào)用spring的service方式

    這篇文章主要介紹了在java的main方法中調(diào)用spring的service方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論

佛山市| 台安县| 济南市| 会泽县| 扎赉特旗| 新巴尔虎右旗| 古浪县| 土默特左旗| 新密市| 炎陵县| 衡阳县| 利津县| 远安县| 武穴市| 芷江| 马龙县| 晴隆县| 革吉县| 合山市| 江门市| 定陶县| 黄山市| 收藏| 横山县| 韶关市| 盘锦市| 广河县| 秭归县| 无极县| 紫金县| 道真| 韶关市| 河曲县| 高州市| 大同市| 大足县| 盖州市| 新化县| 中卫市| 贵定县| 长白|