我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。

前言

我们在启动 SpringBoot 项目时,默认会在控制台打印 Spring logo 和版本号等信息,如下所示。

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

实现原理

SpringBoot 有一个接口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 实现类fallbackBanner,如果存在则使用它来打印 banner 图案。
  3. 否则,则使用默认的SpringBootBanner实现类来打印 banner,也就是我们经常看到Spring图案。
// 获取可用的 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内容,然后启动项目。

在这里插入图片描述

在这里插入图片描述

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 陈皮
 * @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 如下:

在这里插入图片描述

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字符和图案,推荐网址如下:

  • 定制化 ASCII 字符:http://network-science.de/ascii/
  • 定制化 ASCII 图片:https://www.degraeve.com/img2txt.php

本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

Logo

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

更多推荐