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

前言

我们在启动 Spring Boot 项目时,默认会在控制台打印 Spring logo 和版本等信息,如下:

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

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

实现原理

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

  1. package org.springframework.boot;
  2. import java.io.PrintStream;
  3. import org.springframework.core.env.Environment;
  4. /**
  5. * Interface class for writing a banner programmatically.
  6. * 用于以编程方式编写 banner 的接口类
  7. * @since 1.2.0
  8. */
  9. @FunctionalInterface
  10. public interface Banner {
  11. /**
  12. * Print the banner to the specified print stream.
  13. * 将 banner 打印到指定的打印流。
  14. * @param environment the spring environment
  15. * @param sourceClass the source class for the application
  16. * @param out the output print stream
  17. */
  18. void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);
  19. // 用于配置Banner的的枚举值
  20. enum Mode {
  21. // 关闭 banner 打印
  22. OFF,
  23. // 打印 banner 到 控制台
  24. CONSOLE,
  25. // 打印 banner 到日志文件
  26. LOG
  27. }
  28. }

默认 Banner 实现类

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

  1. 项目启动时,会判断是否某些条件成立(项目中是否存在 banner 文件),成立则创建 ImageBannerResourceBanner 类对象,并且使用它们来打印 banner。
  2. 如果不成立检查是否存在我们自定义的 Banner 实现类 fallbackBanner,如果存在则使用它来打印 banner 图案。
  3. 否则,则使用默认的 SpringBootBanner 实现类来打印 banner,也就是我们经常看到 Spring 图案。
  1. // 获取可用的 Banner 实现类
  2. private Banner getBanner(Environment environment) {
  3. Banners banners = new Banners();
  4. banners.addIfNotNull(getImageBanner(environment));
  5. banners.addIfNotNull(getTextBanner(environment));
  6. if (banners.hasAtLeastOneBanner()) {
  7. return banners;
  8. }
  9. if (this.fallbackBanner != null) {
  10. return this.fallbackBanner;
  11. }
  12. // SpringBootBanner 实现类
  13. return DEFAULT_BANNER;
  14. }

ImageBanner

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

  1. class SpringApplicationBannerPrinter {
  2. static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
  3. static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
  4. // 获取 ImageBanner 对象
  5. private Banner getImageBanner(Environment environment) {
  6. // 加载 spring.banner.image.location 指定的文件,文件存在则构建 ImageBanner 对象
  7. String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
  8. if (StringUtils.hasLength(location)) {
  9. Resource resource = this.resourceLoader.getResource(location);
  10. return resource.exists() ? new ImageBanner(resource) : null;
  11. }
  12. // 查找 banner.gif,banner.jpg,banner.png 文件
  13. for (String ext : IMAGE_EXTENSION) {
  14. Resource resource = this.resourceLoader.getResource("banner." + ext);
  15. if (resource.exists()) {
  16. return new ImageBanner(resource);
  17. }
  18. }
  19. return null;
  20. }
  21. }

ResourceBanner

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

  1. class SpringApplicationBannerPrinter {
  2. static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
  3. static final String DEFAULT_BANNER_LOCATION = "banner.txt";
  4. // 获取 ResourceBanner 对象
  5. private Banner getTextBanner(Environment environment) {
  6. String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);
  7. Resource resource = this.resourceLoader.getResource(location);
  8. if (resource.exists()) {
  9. return new ResourceBanner(resource);
  10. }
  11. return null;
  12. }
  13. }

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

SpringBootBanner

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

  1. package org.springframework.boot;
  2. import java.io.PrintStream;
  3. import org.springframework.boot.ansi.AnsiColor;
  4. import org.springframework.boot.ansi.AnsiOutput;
  5. import org.springframework.boot.ansi.AnsiStyle;
  6. import org.springframework.core.env.Environment;
  7. /**
  8. * Default Banner implementation which writes the 'Spring' banner.
  9. */
  10. class SpringBootBanner implements Banner {
  11. // 这个就是我们启动 Springboot 项目时在控制台看到的图案
  12. private static final String[] BANNER = { "", " . ____ _ __ _ _",
  13. " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
  14. " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
  15. " =========|_|==============|___/=/_/_/_/" };
  16. private static final String SPRING_BOOT = " :: Spring Boot :: ";
  17. private static final int STRAP_LINE_SIZE = 42;
  18. @Override
  19. public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
  20. for (String line : BANNER) {
  21. printStream.println(line);
  22. }
  23. String version = SpringBootVersion.getVersion();
  24. version = (version != null) ? " (v" + version + ")" : "";
  25. StringBuilder padding = new StringBuilder();
  26. while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
  27. padding.append(" ");
  28. }
  29. printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
  30. AnsiStyle.FAINT, version));
  31. printStream.println();
  32. }
  33. }

实现 Banner 类

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

  1. package com.chenpi;
  2. import java.io.PrintStream;
  3. import org.springframework.boot.Banner;
  4. import org.springframework.core.env.Environment;
  5. /**
  6. * @Description 自定义 Banner 实现类
  7. * @Author Mr.nobody
  8. * @Date 2021/6/4
  9. * @Version 1.0
  10. */
  11. public class MyBanner implements Banner {
  12. @Override
  13. public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
  14. String banner = " .__ .__ \n"
  15. + " ____ | |__ ____ ____ ______ |__|\n"
  16. + "_/ ___\\| | \\_/ __ \\ / \\ \\____ \\| |\n"
  17. + "\\ \\___| Y \\ ___/| | \\ | |_> > |\n"
  18. + " \\___ >___| /\\___ >___| / | __/|__|\n"
  19. + " \\/ \\/ \\/ \\/ |__| ";
  20. out.println(banner);
  21. }
  22. }

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

  1. package com.chenpi;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class SpringBootBannerApplication {
  6. public static void main(String[] args) {
  7. SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class);
  8. // 设置自定义 Banner
  9. springApplication.setBanner(new MyBanner());
  10. // 启动 SpringBoot
  11. springApplication.run(args);
  12. }
  13. }

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 中定义的变量,例如在配置文件中定义了如下变量:

  1. application.auth=chenpi

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

  1. ${AnsiColor.BRIGHT_GREEN}
  2. ////////////////////////////////////////////////////////////////////
  3. // _ooOoo_ //
  4. // o8888888o //
  5. // 88" . "88 //
  6. // (| ^_^ |) //
  7. // O\ = /O //
  8. // ____/`---'\____ //
  9. // .' \\| |// `. //
  10. // / \\||| : |||// \ //
  11. // / _||||| -:- |||||- \ //
  12. // | | \\\ - /// | | //
  13. // | \_| ''\---/'' | | //
  14. // \ .-\__ `-` ___/-. / //
  15. // ___`. .' /--.--\ `. . ___ //
  16. // ."" '< `.___\_<|>_/___.' >'"". //
  17. // | | : `- \`.;`\ _ /`;.`/ - ` : | | //
  18. // \ \ `-. \_ __\ /__ _/ .-` / / //
  19. // ========`-.____`-.___\_____/___.-`____.-'======== //
  20. // `=---=' //
  21. // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
  22. // 佛祖保佑 永不宕机 永无BUG //
  23. ////////////////////////////////////////////////////////////////////
  24. ${AnsiColor.BRIGHT_CYAN}
  25. Application Version: ${application.version}${application.formatted-version}
  26. Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
  27. By -- ${application.auth}

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

Banner 模式

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

  1. @FunctionalInterface
  2. public interface Banner {
  3. // 用于配置Banner的的枚举值
  4. enum Mode {
  5. // 关闭 banner 打印
  6. OFF,
  7. // 打印 banner 到 控制台
  8. CONSOLE,
  9. // 打印 banner 到日志文件
  10. LOG
  11. }
  12. }

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

  1. package com.chenpi;
  2. import org.springframework.boot.Banner.Mode;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. @SpringBootApplication
  6. public class SpringBootBannerApplication {
  7. public static void main(String[] args) {
  8. SpringApplication springApplication = new SpringApplication(SpringBootBannerApplication.class);
  9. // 关闭 banner
  10. springApplication.setBannerMode(Mode.OFF);
  11. // 启动 SpringBoot
  12. springApplication.run(args);
  13. }
  14. }

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

  1. spring.main.banner-mode=off

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

banner 图生成工具

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

Spring Boot - 自定义 Banner 图案的更多相关文章

  1. Spring Boot自定义Banner

    在2016年的最后一天,借用Spring Boot的Banner向各位程序猿同仁们问候一声:Happy New Year. 接下来我们就来介绍一下这个轻松愉快的自定义banner功能.实现的方式非常简 ...

  2. Spring Boot 自定义 Banner 教程

    我们在启动 SpringBoot 时,控制台会打印 SpringBoot Logo 以及版本信息.有的时候我们需要自己弄个有个性的文本图片.Spring Boot 为我们提供了自定义接口. . ___ ...

  3. Spring boot 自定义banner的在线制作

    目前工作不是很忙,利用闲暇的时间,在给自己不断地充电,提升自己的技术实力. 目前在做一个基于Spring Boot2.x+webmagic+quartz的爬虫项目[hotDog]https://git ...

  4. Spring boot 自定义banner

    Spring Boot启动的时候会在命令行生成一个banner,其实这个banner是可以自己修改的,本文将会将会讲解如何修改这个banner. 首先我们需要将banner保存到一个文件中,网上有很多 ...

  5. Spring Boot定制启动图案

    启动图案 Spring Boot在启动的时候会显示一个默认的Spring的图案,对应的类为SpringBootBanner. . ____ _ __ _ _ /\\ / ___'_ __ _ _(_) ...

  6. spring boot自定义线程池以及异步处理

    spring boot自定义线程池以及异步处理@Async:什么是线程池?线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使 ...

  7. Spring Boot自定义配置与加载

    Spring Boot自定义配置与加载 application.properties主要用来配置数据库连接.日志相关配置等.除了这些配置内容之外,还可以自定义一些配置项,如: my.config.ms ...

  8. Spring Boot 2.X(四):Spring Boot 自定义 Web MVC 配置

    0.准备 Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类.Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一 ...

  9. Spring Boot自定义Redis缓存配置,保存value格式JSON字符串

    Spring Boot自定义Redis缓存,保存格式JSON字符串 部分内容转自 https://blog.csdn.net/caojidasabi/article/details/83059642 ...

随机推荐

  1. k8s 安装 rabbitMQ 单机版

    rabbitMQ docker镜像使用rabbitmq:3.8-management service.yaml文件 apiVersion: v1 kind: Service metadata: nam ...

  2. uni-app&H5&Android混合开发一 || 最全面的uni-app离线打包Android平台教程

    前言: 为什么会写这么一个教程,因为很久之前做过一个对接银行POS我们的系统是使用的H5开发的app应用.但是假如对结果银行相关业务的小伙伴应该都清楚,银行的业务相对于其他的对接方而言安全性比较高,而 ...

  3. 记一次“愉快”的lnmp环境的搭建

    愉快的lnmp环境搭建 后续更新 几个笔记记录 yum remove php-mysql yum -y install cmake autoconf wget gcc-c++ gcc zlib pcr ...

  4. C/C++ 导入表与IAT内存修正

    本章教程中,使用的工具是上次制作的PE结构解析器,如果还不会使用请先看前一篇文章中对该工具的介绍,本章节内容主要复习导入表结构的基础知识点,并通过前面编写的一些小案例,实现对内存的转储与导入表的脱壳修 ...

  5. IDEA 这样设置,好看到爆炸!!!

    Hello,大家好,我是楼下小黑哥. 今天这篇文章是次条视频的文案,这里推荐大家直接看视频学习. IDEA 这样设置,好看到爆炸!!!#01 今天这期我们来分享几个美化 IDEA 设置技巧,让你的 I ...

  6. 【maven】Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.3:site (default-site)

    问题描述 site一点击就报错,如下 Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.3:site (defau ...

  7. PHP基础-PHP中预定义的超全局数组

    预定义数组: 自动全局变量---超全局数组 1. 包含了来自WEB服务器,客户端,运行环境和用户输入的数据 2. 这些数组比较特别 3. 全局范围内自动生效,都可以直接使用这些数组 4. 用户不能自定 ...

  8. Redis数据结构—跳跃表

    目录 Redis数据结构-跳跃表 跳跃表产生的背景 跳跃表的结构 利用跳跃表查询有序链表 Redis跳跃表图示 Redis跳跃表数据结构 小结 Redis数据结构-跳跃表 大家好,我是白泽,最近学校有 ...

  9. C++逆向分析----虚函数与多层继承

    虚函数 C++通过关键字virtual来将函数声明为一个虚函数.当一个类包含虚函数后编译器就会给类的实例对象增加一个虚表指针,所谓的虚表指针就是指向虚表的指针.虚表就是一张地址表,它包含了这个类中所有 ...

  10. 逆向工程初步160个crackme-------7

    这两天有点发烧,被这个疫情搞得人心惶惶的.我们这里是小镇平常过年的时候人来人往的,今年就显得格外的冷清.这是老天帮让在家学习啊,破解完这个crackme明天就去接着看我的加密解密,算了算没几天就开学了 ...