SpringBoot中的Banner

大家在启动一个springboot的项目的时候,都会看到一个图形打印:

在这里插入图片描述

那这个是怎么实现的呢?

一个springboot项目的入口是SpringApplication, 如下源码(只和Banner有关):

public class SpringApplication {
    private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
	private Banner banner;
}

其中的Banner代码如下:一个打印的方法,一个模式的选择:关掉不打印、打印到console、打印到log文件中。

@FunctionalInterface
public interface Banner {

	/**
	 * Print the banner to the specified print stream.
	 * @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);

	/**
	 * An enumeration of possible values for configuring the Banner.
	 */
	enum Mode {

		/**
		 * Disable printing of the banner.
		 */
		OFF,

		/**
		 * Print the banner to System.out.
		 */
		CONSOLE,

		/**
		 * Print the banner to the log file.
		 */
		LOG

	}

}

定位到在SpringApplication中在printBanner中定位banner

public class SpringApplication{
    //其他代码
    //
    private ResourceLoader resourceLoader;
    
    private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Banner.Mode.OFF) { // 模式判断
            return null;
        }
        // 加载资源
        ResourceLoader resourceLoader = (this.resourceLoader != null)
            ? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
        // 打印
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
            resourceLoader, this.banner);
        // log 还是console?
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }
}

接着定位到资源加载器ResourceLoader,为什么有这个呢?继续跟踪:里面有两个方法,一个是获取资源,另一个是获取类加载器。已经被封装,看看是用的那个方法。

public interface ResourceLoader {
    String CLASSPATH_URL_PREFIX = "classpath:";

    Resource getResource(String var1);

    @Nullable
    ClassLoader getClassLoader();
}

继续看SpringApplicationBannerPrinter,一个构造方法

SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
    this.resourceLoader = resourceLoader;
    this.fallbackBanner = fallbackBanner;
}

构造完成之后就是打印banner啦,这里调用了print方法。

// log
public Banner print(Environment environment, Class<?> sourceClass, Log logger) {
    Banner banner = getBanner(environment);
    try {
        logger.info(createStringFromBanner(banner, environment, sourceClass));
    }
    catch (UnsupportedEncodingException ex) {
        logger.warn("Failed to create String for banner", ex);
    }
    return new PrintedBanner(banner, sourceClass);
}
// console
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    Banner banner = getBanner(environment);
    banner.printBanner(environment, sourceClass, out);
    return new PrintedBanner(banner, sourceClass);
}

在这两个方法中都有一个getBanner方法,都是通过该方法从environment中获取出banner

接着看Enviroment

public interface Environment extends PropertyResolver {
    String[] getActiveProfiles();

    String[] getDefaultProfiles();

    /** @deprecated */
    @Deprecated
    boolean acceptsProfiles(String... var1);

    boolean acceptsProfiles(Profiles var1);
}

查看getDefaultProfiles方法的实现:

//
public String[] getDefaultProfiles() {
    return StringUtils.toStringArray(this.doGetDefaultProfiles());
}

// doGetDefaultProfiles()
protected Set<String> doGetDefaultProfiles() {
    synchronized(this.defaultProfiles) {
        if (this.defaultProfiles.equals(this.getReservedDefaultProfiles())) {
            String profiles = this.getProperty("spring.profiles.default");
            if (StringUtils.hasText(profiles)) {
                this.setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(profiles)));
            }
        }

        return this.defaultProfiles;
    }
}

To be continue

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐