返回

SpringBoot——banner解析

发布时间:2023-04-06 18:03:52 297
# html# spring# java# 信息# 扫描

banner演示

SpringBoot项目启动时会在控制台打印一个默认的LOGO,这个LOGO就是我们要讲的banner。

制作自己的banner

实际上,Spring Boot 支持自定义 logo 的功能。让我们来看看如何实现的。 只要你在 resources 目录下放置名为 banner.txt、banner.gif 、banner.jpg 或 banner.png 的文件,Spring Boot 会自动加载,将其作为启动时打印的 logo。

  • 对于文本文件,Spring Boot 会将其直接输出。
  • 对于图像文件( banner.gif 、banner.jpg 或 banner.png ),Spring Boot 会将图像转为 ASCII 字符,然后输出。

变量

banner.txt 文件中还可以使用变量来设置字体、颜色、版本号。

变量 描述
${application.version} MANIFEST.MF 中定义的版本。如:1.0
${application.formatted-version} MANIFEST.MF 中定义的版本,并添加一个 v 前缀。如:v1.0
${spring-boot.version} Spring Boot 版本。如:2.1.1.RELEASE.
${spring-boot.formatted-version} Spring Boot 版本,并添加一个 v 前缀。如:v2.1.1.RELEASE
${Ansi.NAME} (or ${AnsiColor.NAME}
${AnsiBackground.NAME}${AnsiStyle.NAME})
ANSI 颜色、字体。更多细节,参考:AnsiPropertySource
${application.title} MANIFEST.MF 中定义的应用名。

示例: 在 Spring Boot 项目中的 resources 目录下添加一个名为 banner.txt 的文件,内容如下:

${AnsiColor.BRIGHT_YELLOW}${AnsiStyle.BOLD}
 ________  ___  ___  ________   ___       __   ___  ___
|\   ___ \|\  \|\  \|\   ___  \|\  \     |\  \|\  \|\  \
\ \  \_|\ \ \  \\\  \ \  \\ \  \ \  \    \ \  \ \  \\\  \
 \ \  \ \\ \ \  \\\  \ \  \\ \  \ \  \  __\ \  \ \  \\\  \
  \ \  \_\\ \ \  \\\  \ \  \\ \  \ \  \|\__\_\  \ \  \\\  \
   \ \_______\ \_______\ \__\\ \__\ \____________\ \_______\
    \|_______|\|_______|\|__| \|__|\|____________|\|_______|
${AnsiBackground.WHITE}${AnsiColor.RED}${AnsiStyle.UNDERLINE}
:: Spring Boot ::             (v${spring-boot.version})
:: Spring Boot Tutorial ::    (v1.0.0)

注:${} 设置字体颜色的变量之间不能换行或空格分隔,否则会导致除最后一个变量外,都不生效。

 

启动应用后,控制台将打印如下 logo:

推荐两个生成字符画的网站,可以将生成的字符串放入这个banner.txt 文件:

  • http://www.network-science.de/ascii/
  • http://patorjk.com/software/taag/

配置

application.properties 中与 Banner 相关的配置:

# banner 模式。有三种模式:console/log/off
# console 打印到控制台(通过 System.out)
# log - 打印到日志中
# off - 关闭打印
spring.main.banner-mode = off
# banner 文件编码
spring.banner.charset = UTF-8
# banner 文本文件路径
spring.banner.location = classpath:banner.txt
# banner 图像文件路径(可以选择 png,jpg,gif 文件)
spring.banner.image.location = classpath:banner.gif
used).
# 图像 banner 的宽度(字符数)
spring.banner.image.width = 76
# 图像 banner 的高度(字符数)
spring.banner.image.height =
# 图像 banner 的左边界(字符数)
spring.banner.image.margin = 2
# 是否将图像转为黑色控制台主题
spring.banner.image.invert = false

编程方式设置banner的兜底逻辑

@SpringBootApplication
@MapperScan("com.yibo.source.code.mapper")//扫描Mapper接口
public class Application {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.setBanner(new ResourceBanner(new ClassPathResource("banner_bak.txt")));
        springApplication.run(args);
    }
}

banner_bak.txt

////////////////////////////////////////////////////////////////////
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//             佛祖保佑          永无故障         永不修改             //
////////////////////////////////////////////////////////////////////

输出:

注意:

默认,Spring Boot 会注册一个 SpringBootBanner 的单例 Bean,用来负责打印 Banner。

 

如果想完全个人定制 Banner,可以这么做:先实现 org.springframework.boot.Banner#printBanner 接口来自己定制 Banner。在将这个 Banner 通过 SpringApplication.setBanner(…) 方法注入 Spring Boot。

banner获取原理

banner的入口在SpringApplication的run方法中:

public class SpringApplication {
	public ConfigurableApplicationContext run(String... args) {
		......
		Banner printedBanner = printBanner(environment);
	}
}

接着跟进printBanner(environment);方法

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);
	//判断是否打印到日志中打印到日志中
	if (this.bannerMode == Mode.LOG) {
		return bannerPrinter.print(environment, this.mainApplicationClass, logger);
	}
	//直接打印到控制台
	return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

接着跟进bannerPrinter.print()方法

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);
}

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 environment)方法

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;
	}
	return DEFAULT_BANNER;
}

getImageBanner(environment)

  • 可以通过spring.banner.image.location指定位置
  • 可以使用的图片格式为"gif", "jpg", "png"
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
private Banner getImageBanner(Environment environment) {
	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;
	}
	for (String ext : IMAGE_EXTENSION) {
		Resource resource = this.resourceLoader.getResource("banner." + ext);
		if (resource.exists()) {
			return new ImageBanner(resource);
		}
	}
	return null;
}

getTextBanner(environment)

  • 可以通过spring.banner.location指定位置
  • 默认名字为banner.txt
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
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步骤

banner输出原理

默认输出:

  • 先输出banner指定内容
  • 获取version信息
  • 文本内容前后对其
  • 文本内容染色
  • 输出文本内容
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();
	}

}

文本输出

  • 可以通过spring.banner.charset指定字符集
  • 获取文本内容
  • 替换占位符
  • 输出文本内容
private static class Banners implements Banner {

	private final List banners = new ArrayList<>();

	public void addIfNotNull(Banner banner) {
		if (banner != null) {
			this.banners.add(banner);
		}
	}

	@Override
	public void printBanner(Environment environment, Class sourceClass, PrintStream out) {
		for (Banner banner : this.banners) {
			banner.printBanner(environment, sourceClass, out);
		}
	}

}

public class ResourceBanner implements Banner {
	@Override
	public void printBanner(Environment environment, Class sourceClass, PrintStream out) {
		try {
			String banner = StreamUtils.copyToString(this.resource.getInputStream(),
					environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8));

			for (PropertyResolver resolver : getPropertyResolvers(environment, sourceClass)) {
				banner = resolver.resolvePlaceholders(banner);
			}
			out.println(banner);
		}
		catch (Exception ex) {
			logger.warn(
					"Banner not printable: " + this.resource + " (" + ex.getClass() + ": '" + ex.getMessage() + "')",
					ex);
		}
	}
}

图片输出

  • 可以通过spring.banner.image.*设置图片属性
  • 读取图片文件流
  • 输出图片内容
private static class Banners implements Banner {

	private final List banners = new ArrayList<>();

	public void addIfNotNull(Banner banner) {
		if (banner != null) {
			this.banners.add(banner);
		}
	}

	@Override
	public void printBanner(Environment environment, Class sourceClass, PrintStream out) {
		for (Banner banner : this.banners) {
			banner.printBanner(environment, sourceClass, out);
		}
	}

}

public class ImageBanner implements Banner {

	private static final String PROPERTY_PREFIX = "spring.banner.image.";

	@Override
	public void printBanner(Environment environment, Class sourceClass, PrintStream out) {
		String headless = System.getProperty("java.awt.headless");
		try {
			System.setProperty("java.awt.headless", "true");
			printBanner(environment, out);
		}
		catch (Throwable ex) {
			logger.warn("Image banner not printable: " + this.image + " (" + ex.getClass() + ": '" + ex.getMessage()
					+ "')");
			logger.debug("Image banner printing failure", ex);
		}
		finally {
			if (headless == null) {
				System.clearProperty("java.awt.headless");
			}
			else {
				System.setProperty("java.awt.headless", headless);
			}
		}
	}

	private void printBanner(Environment environment, PrintStream out) throws IOException {
		int width = getProperty(environment, "width", Integer.class, 76);
		int height = getProperty(environment, "height", Integer.class, 0);
		int margin = getProperty(environment, "margin", Integer.class, 2);
		boolean invert = getProperty(environment, "invert", Boolean.class, false);
		Frame[] frames = readFrames(width, height);
		for (int i = 0; i < frames.length; i++) {
			if (i > 0) {
				resetCursor(frames[i - 1].getImage(), out);
			}
			printBanner(frames[i].getImage(), margin, invert, out);
			sleep(frames[i].getDelayTime());
		}
	}
}

参考: https://www.cnblogs.com/jingmoxukong/p/10159493.html

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
SpringBoot——bean解析 2023-04-06 14:51:41