SpringBoot 自定义Banner

SpringBoot自定义Banner

SpringBoot项目启动的时候会输出一个Spring的图标。

SpringBoot 自定义Banner_第1张图片

思考

  • 它是在哪个环节的时候输出的呢?
  • 是否可以自定义图标呢?

源码分析

通常我们SpringBoot项目是通过SpringBoot.run(Appcation.class)启动的。

run()

public ConfigurableApplicationContext run(String... args) {
		try {
            // 关键是这两行 
            // 第一行是初始化环境信息也就是会将我们配置文件中的内容,或者是System.getProperties()中的信息进行封装
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            // 通过环节信息来构建Banner并输出对于的内容
			Banner printedBanner = printBanner(environment);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		return context;
}

printBanner()

private Banner.Mode bannerMode = Banner.Mode.CONSOLE;


private Banner printBanner(ConfigurableEnvironment environment) {
    	// 判断横幅的模式 是否为禁用 ,默认是输出到控制台
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(null);
    	// 创建一个SpringApplicationBannerPrinter对象
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
    	// 判断横幅模式是否为输出到日志
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
    	// 默认情况会走到这里
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

Banner.Mode

enum Mode {
		/**
		 * 禁用横幅的打印
		 */
		OFF,

		/**
		 * 将横幅输出到System.out
		 */
		CONSOLE,

		/**
		 * 将横幅输出到日志文件中
		 */
		LOG

	}

SpringApplicationBannerPrinter.print()

Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    	// 根据环节信息创建一个Banner
		Banner banner = getBanner(environment);
    	// 实际输出Banner的地方
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
}

getBanner()

// 	private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private Banner getBanner(Environment environment) {
		Banners banners = new Banners();
    	// 判断是否存在image的横幅
		banners.addIfNotNull(getImageBanner(environment));
    	// 判断是否存在文本的横幅
		banners.addIfNotNull(getTextBanner(environment));
		if (banners.hasAtLeastOneBanner()) {
			return banners;
		}
		if (this.fallbackBanner != null) {
			return this.fallbackBanner;
		}
    	// 这里如果在配置中没有得到Banner的话,则会使用SpringBoot默认的
		return DEFAULT_BANNER;
}
// 从当前环境中取出spring.banner.image.location 
// 判断这个路径下是否存在文件,存在则创建一个ImageBanner
// 不存在这尝试读取类路径下的banner.gif, banner.jpg", banner.png 
// 都不存在则返回一个NULL
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;
		}
		for (String ext : IMAGE_EXTENSION) {
			Resource resource = this.resourceLoader.getResource("banner." + ext);
			if (resource.exists()) {
				return new ImageBanner(resource);
			}
		}
		return null;
}

// 从当前环境中取出spring.banner.location配置的值 默认是banner.txt 可以自定义。通过这个路径来创建一个ResourceBanner
private Banner getTextBanner(Environment environment) {
		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 ex) {
			// Ignore
		}
		return null;
	}

SpringBootBanner

class SpringBootBanner implements Banner {

	private static final String[] BANNER = { "", "  .   ____          _            __ _ _",
			" /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
			" \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
			" =========|_|==============|___/=/_/_/_/" };

	private static final String SPRING_BOOT = " :: Spring Boot :: ";

	private static final int STRAP_LINE_SIZE = 42;

	@Override
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
		for (String line : BANNER) {
			printStream.println(line);
		}
		String version = SpringBootVersion.getVersion();
		version = (version != null) ? " (v" + version + ")" : "";
		StringBuilder padding = new StringBuilder();
		while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
			padding.append(" ");
		}

		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
				AnsiStyle.FAINT, version));
		printStream.println();
	}

}

这里可以看见BANNER是一个字符串数组,实际打印的也就是这个数组的值。也就是我们的Spring图标以及一些版本信息。

小结

从源码中分析得出,在不配置spring.banner.locationspring.banner.image.location的情况下,SpringBoot默认会使用SpringBootBanner来进行输出。输出的则是Spring的图标。

当我们想自定义图标的话,则可以使用spring.banner.location来指定一个横幅文件的位置,或者直接在类路径下创建一个banner.txt,并把横幅的内容写入到里面。

实践

创建一个banner.txt,并写入程序员万岁!;

输出效果

image-20240121145819663

感觉很low。如何让他变的跟Spring那个图标一样好看呢。

Spring Boot自定义启动Banner在线生成工具

SpringBoot 自定义Banner_第2张图片

替换banner.tet内容,效果。

SpringBoot 自定义Banner_第3张图片

补充

纯字体的网站

  • (推荐)https://www.bootschool.net/ascii

  • http://patorjk.com/software/taag/

  • http://www.network-science.de/ascii/

图片风

  • (推荐)https://www.bootschool.net/ascii-art/animals

  • https://www.degraeve.com/img2txt.php

内置变量

  • spring-boot.version:SpringBoot的版本号
  • spring-boot.formatted-version:带v的版本号

SpringBoot 自定义Banner_第4张图片

总结

https://www.bootschool.net/ascii-art/animals

  • https://www.degraeve.com/img2txt.php

内置变量

  • spring-boot.version:SpringBoot的版本号
  • spring-boot.formatted-version:带v的版本号

[外链图片转存中…(img-kzLyUrAu-1705820973870)]

总结

直接在类路径下创建banner.txt来替换SpringBoot默认的输出最为方便,想要美化的话,可以通过一些工具来进行生成。

你可能感兴趣的:(Java,spring,boot,后端,java)