Spring Boot - 自定义 Banner 图案

我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复【资料】,即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板。

前言


我们在启动 Spring Boot 项目时,默认会在控制台打印 Spring logo 和版本等Spring Boot - 自定义 Banner 图案

这就是 Spring Boot 的 Banner 打印功能,其实我们可以自定义打印的 banner ,也可以禁用和启用打印 banner 功能。在真实项目中,我们一般不会去自定义 banner 图案,它其实就是项目启动时打印图案或者文字而已,没实际意义。推荐在自己个人项目玩玩这个彩蛋即可,顺便简单了解下它内部实现原理。

Spring Boot - 自定义 Banner 图案

比如,自定义一个 banner 之后,项目启动控制台打印如下所示:

Spring Boot - 自定义 Banner 图案 Spring Boot - 自定义 Banner 图案

实现原理


Spring Boot 有一个接口 org.springframework.boot.Banner 专门实现这个操作。要想自定义打印 banner ,只要自定义一个类实现这个接口,重写 printBanner 方法进行打印即可。Springboot 项目启动时,会创建我们的实现类对象,并调用对象的 printBanner 方法。

package org.springframework.boot;  import java.io.PrintStream;  import org.springframework.core.env.Environment;  /**  * Interface class for writing a banner programmatically.  * 用于以编程方式编写 banner 的接口类  * @since 1.2.0  */ @FunctionalInterface public interface Banner {  	/** 	 * Print the banner to the specified print stream. 	 * 将 banner 打印到指定的打印流。 	 * @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);  	// 用于配置Banner的的枚举值 	enum Mode { 		// 关闭 banner 打印 		OFF,         // 打印 banner 到 控制台 		CONSOLE, 		// 打印 banner 到日志文件 		LOG 	} } 

默认 Banner 实现类


Springboot 已经有几个自带的 Banner 实现类,Springboot 启动时会根据条件选择不同的 Banner 实现类进行打印 banner 信息。主要是 ImageBannerResourceBannerSpringBootBanner 这三个实现类。

  1. 项目启动时,会判断是否某些条件成立(项目中是否存在 banner 文件),成立则创建 ImageBannerResourceBanner 类对象,并且使用它们来打印 banner。
  2. 如果不成立检查是否存在我们自定义的 Banner 实现类 fallb// 获取可用的 Banner 实现类 private Banner getBanner(Environment environment) { Banners banners = new Banners(); banners.addIfNotNull(getImageBanner(environment)); banners.addIfNotNull(getTextBanner(environment)); if (banners.hasAtLeastOneBanner()) { return banners; } if (this.fallbackBanner != null) { return this.fallbackBanner; } // SpringBootBanner 实现类 return DEFAULT_BANNER; }

    ImageBanner


    org.springframework.boot.ImageBanner 类是专门加载和打印图片 banner 的。它检查配置文件 application.proeprties 是否有配置的 spring.banner.image.location 变量的值,这个值可用来指定要加载的图片,如果存在则构建 ImageBanner 对象。如果没有配置变量,则还会检查 Classpath 下是否存在以 banner 开头,以 .gif.jpg.png 结尾的图片文件,如果有也会构建 ImageBanner 对象。

    class SpringApplicationBannerPrinter {  	static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";  	static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };  	// 获取 ImageBanner 对象 	private Banner getImageBanner(Environment environment) { 	    // 加载 spring.banner.image.location 指定的文件,文件存在则构建 ImageBanner 对象 		String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY); 		if (StringUtils.hasLength(location)) { 			Resource resource = this.resourceLoader.getResource(location); 			return resource.exists() ? new ImageBanner(resource) : null; 		} 		// 查找 banner.gif,banner.jpg,banner.png 文件 		for (String ext : IMAGE_EXTENSION) { 			Resource resource = this.resourceLoader.getResource("banner." + ext); 			if (resource.exists()) { 				return new ImageBanner(resource); 			} 		} 		return null; 	} } 

    ResourceBanner


    org.springframework.boot.ResourceBanner 类是专门加载和打印字符 banner 的。它检查配置文件 application.proeprties 是否有配置的 spring.banner.location 变量的值,这个值可用来指定要加载的文件,如果存在则构建 ResourceBanner 对象。如果没有配置变量,则还会检查资源路径下是否存在 banner.txt 文件,如果存在也会构建 ResourceBanner 对象。

    class SpringApplicationBannerPrinter {  	static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";  	static final String DEFAULT_BANNER_LOCATION = "banner.txt";  	// 获取 ResourceBanner 对象 	private Banner getTextBanner(Environment environment) { 		String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION); 		Resource resource = this.resourceLoader.getResource(location); 		if (resource.exists()) { 			return new ResourceBanner(resource); 		} 		return null; 	} } 

    如果想要自定义 banner,我们一般在项目的 resources 资源目录下创建 banner.txt 文件,然后在里面填入我们想要的打印的文字内容即可。例如我在 banner.txt 文件中填充了 Chen Pi 内容,然后启动项目。

    Spring Boot - 自定义 Banner 图案
    Spring Boot - 自定义 Banner 图案

    SpringBootBanner

    如果项目没有设置以上两种自定义的 banner(ImageBanner 和 ResourceBanner),则默认情况下,会使用 SpringBootBanner 实现类打印 banner ,也就是我们启动 Springboot 项目时在控制台看到的打印 Spring 图案。源码如下:

    package org.springframework.boot;  import java.io.PrintStream;  import org.springframework.boot.ansi.AnsiColor; import org.springframework.boot.ansi.AnsiOutput; import org.springframework.boot.ansi.AnsiStyle; import org.springframework.core.env.Environment;  /**  * Default Banner implementation which writes the 'Spring' banner.  */ class SpringBootBanner implements Banner { 	// 这个就是我们启动 Springboot 项目时在控制台看到的图案 	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 类

    前面说我们可以实现 Banner 类,重写打印方法,实现自定义 banner 打印功能。

    package com.chenpi;  import java.io.PrintStream; import org.springframework.boot.Banner; import org.springframework.core.env.Environment;  /**  * @Description 自定义 Banner 实现类  * @Author Mr.nobody  * @Date 2021/6/4  * @Version 1.0  */ public class MyBanner implements Banner {      @Override     public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {        String banner = "       .__                           .__ n"           + "  ____ |  |__   ____   ____   ______ |__|n"           + "_/ ___\|  |  \_/ __ \ /    \  \____ \|  |n"           + "\  \___|   Y  \  ___/|   |  \ |  |_> >  |n"           + " \___  >___|  /\___  >___|  / |   __/|__|n"           + "     \/     \/     \/     \/  |__|       ";        out.println(banner);     } } 

    创建自定义的 Banner 实现类对象,设置到 SpringApplication 类对象的 banner 属性,最终这个属性的值会会被赋值到 SpringApplicationBannerPrinter 对象的 fallbackBanner 属性中,感兴趣的可以启动 debug 跟踪下。

    package com.chenpi;  import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication public class SpringBootBannerApplication { 	public static void main(String[] args) { 		SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class); 		// 设置自定义 Banner 		springApplication.setBanner(new MyBanner()); 		// 启动 SpringBoot 		springApplication.run(args); 	} } 

    Banner 样式控制


    文章一开始的佛祖图形,你会发现是翠绿色的。其实 Springboot 支持我们修改 banner 的颜色,字体斜体,粗体等样式。SpringBoot 为我们提供了三个枚举类来设定这些样式。

    1. AnsiColor:设定字符的前景色;参考 org.springframework.boot.ansi.AnsiColor 枚举类。
    2. AnsiBackground:设定字符的背景色;参考 org.springframework.boot.ansi.AnsiBackground 枚举类。
    3. AnsiStyle:设定字符的加粗、斜体、下划线等等;参考 org.springframework.boot.ansi.AnsiStyle 枚举类。

    而且,在 banner.txt 文件中还可以引用一些全局变量,例如:

    1. ${spring-boot.version}:Spring Boot 版本号;
    2. ${spring-boot.formatted-version}:格式化后的 Spring Boot 版本号信息
    3. ${application.version}:MANIFEST.MF 文件中的版本号;
    4. ${application.formatted-version}:格式化后的 MANIFEST.MF 文件中的版本号信息;

    不仅如此,还可以引用我们在配置文件 application.properties 中定义的变量,例如在配置文件中定义了如下变量:

    application.auth=chenpi 

    定义的 banner.txt 文件内容如下:

    ${AnsiColor.BRIGHT_GREEN}  //                          _ooOoo_                               // //                         o8888888o                              // //                         88" . "88                              // //                         (| ^_^ |)                              // //                         O  =  /O                              // //                      ____/`---'____                           // //                    .'  \|     |//  `.                         // //                   /  \|||  :  |||//                          // //                  /  _||||| -:- |||||-                         // //                  |   | \  -  /// |   |                       // //                  | _|  ''---/''  |   |                       // //                    .-__  `-`  ___/-. /                       // //                ___`. .'  /--.--  `. . ___                     // //              ."" '<  `.____<|>_/___.'  >'"".                  // //            | | :  `- `.;` _ /`;.`/ - ` : | |                 // //               `-.   _ __ /__ _/   .-` /  /                 // //      ========`-.____`-.________/___.-`____.-'========         // //                           `=---='                              // //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        // //            佛祖保佑       永不宕机     永无BUG                     //  ${AnsiColor.BRIGHT_CYAN} Application Version: ${application.version}${application.formatted-version} Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}  By -- ${application.auth} 

    启动项目,会在控制台打印的 banner 如下:

    Spring Boot - 自定义 Banner 图案

    Banner 模式


    在 Banner 接口中有定义一个枚举类,这个枚举定义了配置 Banner 的可能枚举值,如下:

    @FunctionalInterface public interface Banner {  	// 用于配置Banner的的枚举值 	enum Mode { 		// 关闭 banner 打印 		OFF,         // 打印 banner 到 控制台 		CONSOLE, 		// 打印 banner 到日志文件 		LOG 	} } 

    所以我们可以选择关闭 banner,banner 打印到控制台还是日志文件,如下:

    package com.chenpi;  import org.springframework.boot.Banner.Mode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication public class SpringBootBannerApplication {     public static void main(String[] args) {          SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class);          // 关闭 banner          springApplication.setBannerMode(Mode.OFF);          // 启动 SpringBoot          springApplication.run(args);     } } 

    也可以配置文件中设置此值,如下

    spring.main.banner-mode=off 

    如果启动类跟配置文件中都配置了对banner开关的设置,配置文件中设置的banner开关会优先于启动类中设置的开关。

    banner 图生成工具


    可能有人会问佛祖的图案怎么编辑出来的,其实网上有很多工具可以根据我们输入的内容或者图片,个性化制作ASCII字符和图案,推荐网址如下:

版权声明:玥玥 发表于 2021-06-06 23:40:33。
转载请注明:Spring Boot - 自定义 Banner 图案 | 女黑客导航