您现在的位置是:首页 >技术杂谈 >Spring Boot banner详解网站首页技术杂谈
Spring Boot banner详解
Spring Boot 3.x系列文章
自定义banner
Spring Boot 默认打印的banner是这样的,Java工程师看都看腻了。
一般的公司如果有自己脚手架,都会选择自定义banner,放一个公司Logo或者框架别名。
简易版banner
首先生成一个自己的banner,比如我生成的
生成的网站很多,可以用"banner 生成器"自行搜索
把生成的内容copy到txt中,命名为"banner.txt
"(UTF-8),然后放到resources
下。
启动Spring Boot 即可看到效果。
自定义banner路径
上述的banner.txt 只能放在resources
根目录下,不能在resources子目录或其他的目录,使用spring.banner.location
指定该文件的路径,如果该文件不是UTF-8编码,使用spring.banner.charset
指定文件编码,比如我将文件放到resources的子目录static中。
自定义banner 样式
光一个Logo也还是太单调,如果能再打印个Spring Boot 版本、应用程序版本就更好了,Spring Boot 都给我们提供了相关变量,可以在banner.txt中使用。
- ${application.version} 应用程序版本
- ${application.formatted-version} 格式化的应用程序版本,前缀是
v
- ${spring-boot.version} Spring Boot框架版本
- ${spring-boot.formatted-version} 格式化的Spring Boot框架版本,前缀是
v
- ${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})
给文字加颜色,加背景,加样式,NAME的值可以在这里获取ansi - ${application.title} 应用程序的标题
如图我给banner 加上了颜色,加上了版本
配置如下:
${AnsiColor.GREEN}
/$$$$$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$$ /$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$ /$$ /$$
/$$__ $$ /$$__ $$| $$__ $$| $$$ | $$ |_ $$_/|__ $$__//$$__ $$ /$$__ $$| $$ /$$//$$__ $$ /$$__ $$| $$ /$$/
| $$ \__/| $$ \__/| $$ $$| $$$$| $$ | $$ | $$ | $$ \__/| $$ $$ $$ /$$/| $$ \__/| $$ $$ $$ /$$/
| $$ | $$$$$$ | $$ | $$| $$ $$ $$ /$$$$$$| $$ | $$ | $$$$$$ | $$$$$$$$ $$$$/ | $$$$$$ | $$$$$$$$ $$$$/
| $$ \____ $$| $$ | $$| $$ $$$$|______/| $$ | $$ \____ $$| $$__ $$ $$/ \____ $$| $$__ $$ $$/
| $$ $$ /$$ $$| $$ | $$| $$ $$$ | $$ | $$ /$$ $$| $$ | $$ | $$ /$$ $$| $$ | $$ | $$
| $$$$$$/| $$$$$$/| $$$$$$$/| $$ $$ /$$$$$$ | $$ | $$$$$$/| $$ | $$ | $$ | $$$$$$/| $$ | $$ | $$
\______/ \______/ |_______/ |__/ \__/ |______/ |__/ \______/ |__/ |__/ |__/ \______/ |__/ |__/ |__/
${AnsiColor.DEFAULT}
::Spring Boot Version: ${AnsiColor.RED}${spring-boot.formatted-version}${AnsiColor.DEFAULT}
::Application Version: ${AnsiColor.RED}${application.formatted-version}${AnsiColor.DEFAULT}
- 如果颜色不起作用,那就是需要开启一下:
spring.output.ansi.enabled=always
- ${AnsiColor.DEFAULT} 是将颜色重置,防止前面的颜色影响下面的
- ${application.formatted-version} 、 ${application.version}、 ${application.title} 要使用jar包启动才会打印
- banner.txt 中可以配置环境变量environment中的任何键值
使用图片做banner
在Spring Boot 3.x版本中已经不被支持
编码方式定义banner
自定义一个CustomBanner类,实现Banner接口
,如:
import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
public class CustomBanner implements Banner {
public static final String BANNER = " /$$$$$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$$$ /$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$$$$$ /$$ /$$
" +
" /$$__ $$ /$$__ $$| $$__ $$| $$$ | $$ |_ $$_/|__ $$__//$$__ $$ /$$__ $$| $$ /$$//$$__ $$ /$$__ $$| $$ /$$/
" +
"| $$ \__/| $$ \__/| $$ \ $$| $$$$| $$ | $$ | $$ | $$ \__/| $$ \ $$ \ $$ /$$/| $$ \__/| $$ \ $$ \ $$ /$$/
" +
"| $$ | $$$$$$ | $$ | $$| $$ $$ $$ /$$$$$$| $$ | $$ | $$$$$$ | $$$$$$$$ \ $$$$/ | $$$$$$ | $$$$$$$$ \ $$$$/
" +
"| $$ \____ $$| $$ | $$| $$ $$$$|______/| $$ | $$ \____ $$| $$__ $$ \ $$/ \____ $$| $$__ $$ \ $$/
" +
"| $$ $$ /$$ \ $$| $$ | $$| $$\ $$$ | $$ | $$ /$$ \ $$| $$ | $$ | $$ /$$ \ $$| $$ | $$ | $$
" +
"| $$$$$$/| $$$$$$/| $$$$$$$/| $$ \ $$ /$$$$$$ | $$ | $$$$$$/| $$ | $$ | $$ | $$$$$$/| $$ | $$ | $$
" +
" \______/ \______/ |_______/ |__/ \__/ |______/ |__/ \______/ |__/ |__/ |__/ \______/ |__/ |__/ |__/
";
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
printStream.println(BANNER);
}
}
SpringApplication 中配置banner
SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
springApplication.setBanner(new CustomBanner());
如果在类路径中存在
banner.txt
在会优先使用banner.txt
禁用banner
Spring Boot 提供了spring.main.banner-mode
配置,OFF
-关闭banner打印,CONSOLE
-使用System.out打印banner,log文件不会记录,LOG
-打印到log文件
另外同样可以用springApplication.setBannerMode(Banner.Mode.OFF);
方式设置banner
加载打印原理
在之前的《Spring Boot 框架整体启动流程详解》中,我们看到有一步是
//打印banner
Banner printedBanner = printBanner(environment);
这一步就是加载打印banner的核心。
private Banner printBanner(ConfigurableEnvironment environment) {
//如果bannerMode是关闭的,就会不打印banner
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
//获取资源加载器,如果当前没有就使用默认的资源加载器
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(null);
//创建一个SpringBoot应用程序的banner打印类,如果通过setBanner设置,this.banner会有值
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
//如果bannerMode 是打印到log文件
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
//默认打印到控制台
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
先看下如何打印到log文件:
Banner print(Environment environment, Class<?> sourceClass, Log logger) {
//获取Banner对象
Banner banner = getBanner(environment);
try {
//使用log 的info 级别打印
logger.info(createStringFromBanner(banner, environment, sourceClass));
}
catch (UnsupportedEncodingException ex) {
logger.warn("Failed to create String for banner", ex);
}
//创建一个打印banner的装饰器bean,允许后期再次使用
return new PrintedBanner(banner, sourceClass);
}
如何获取的Banner对象:
private Banner getBanner(Environment environment) {
//获取txt文本banner
Banner textBanner = getTextBanner(environment);
if (textBanner != null) {
return textBanner;
}
//fallbackBanner 为前期通过setBanner设置的自定义banner
//可见如果两者同时设置,优先使用的txt文本banner
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
//都没有,返回一个默认的SpringBootBanner
return DEFAULT_BANNER;
}
如果获取txt文本banner:
private Banner getTextBanner(Environment environment) {
//从环境变量中获取spring.banner.location指定的banner地址,如果没有,使用banner.txt
String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);
//获取指定的资源对象
Resource resource = this.resourceLoader.getResource(location);
try {
//资源存在,并且资源路径中不包含liquibase-core
if (resource.exists() && !resource.getURL().toExternalForm().contains("liquibase-core")) {
//创建一个从源打印的banner对象,实现了Banner接口
return new ResourceBanner(resource);
}
}
catch (IOException ex) {
// Ignore
}
return null;
}
获取到文本banner的ResourceBanner资源对象后,回到print(Environment environment, Class<?> sourceClass, Log logger)
这个方法中,接下来就是要把获取到banner对象打印出来,createStringFromBanner
将获取到banner对象,调用其中的printBanner
方法,把输出流转为UTF-8的字符串输出到log文件中。
private String createStringFromBanner(Banner banner, Environment environment, Class<?> mainApplicationClass)
throws UnsupportedEncodingException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
banner.printBanner(environment, mainApplicationClass, new PrintStream(baos));
String charset = environment.getProperty("spring.banner.charset", "UTF-8");
return baos.toString(charset);
}
ResourceBanner的printBanner方法:
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
try {
//从流读取banner.txt 字符串,使用spring.banner.charset编码,或者UTF-8
String banner = StreamUtils.copyToString(this.resource.getInputStream(),
environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8));
//获取用于解析占位符的所有属性源
for (PropertyResolver resolver : getPropertyResolvers(environment, sourceClass)) {
//解析banner,使用PropertyPlaceholderHelper工具类解析
banner = resolver.resolvePlaceholders(banner);
}
//输出到流中
out.println(banner);
}
catch (Exception ex) {
logger.warn(LogMessage.format("Banner not printable: %s (%s: '%s')", this.resource, ex.getClass(),
ex.getMessage()), ex);
}
}
bannerPrinter.print(environment, this.mainApplicationClass, System.out);
打印到控制台的逻辑也是一样的,只是直接输出到控制台
Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
Banner banner = getBanner(environment);
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
总结
通过图来总结一下整个流程
作者其他要推荐的文章,欢迎来学习:
Prometheus 系列文章
- Prometheus 的介绍和安装
- 直观感受PromQL及其数据类型
- PromQL之选择器和运算符
- PromQL之函数
- Prometheus 告警机制介绍及命令解读
- Prometheus 告警模块配置深度解析
- Prometheus 配置身份认证
- Prometheus 动态拉取监控服务
- Prometheus 监控云Mysql和自建Mysql
Grafana 系列文章,版本:OOS v9.3.1
- Grafana 的介绍和安装
- Grafana监控大屏配置参数介绍(一)
- Grafana监控大屏配置参数介绍(二)
- Grafana监控大屏可视化图表
- Grafana 查询数据和转换数据
- Grafana 告警模块介绍
- Grafana 告警接入飞书通知
Spring Boot Admin 系列