写在前面
首先要祝小伙伴们中秋+国庆双节快乐,八天的假期属实有点过瘾。不过我相信肯定还是有很多小伙伴放假期间还依然坚守在一线的开发岗位,为保证我们后台服务的稳定付出着辛苦,在这里向你们致敬,祝加班费拿到手软,不辜负自己的付出和努力。
既然是放假,那我们今天就不说枯燥的理论和冗长的源码。来聊点有意思的,相信用过SpringBoot的小伙伴在本地启动服务时都会看到控制台会打印出SpringBoot的LOGO,就像下面这样:
这里我们就可以提出疑问,这个LOGO是在何时,通过什么样的方式打印到控制台的呢?如果我们想要定制属于自己的LOGO,具体要怎么做呢?带着这几个问题,我们来看一下SpingBoot自定义LOGO的方法和原理。
要探究SpringBoot LOGO的打印,我们首先要看一下SpringBoot的启动流程。
要执行SpringBoot启动,就要运行@SpringBootApplication注解所标注的主配置类的
在main()方法中,可以看到SpringApplication调用静态方法run()执行容器启动,跟踪一下代码,最终会调用SpringBootApplication.run(String...args)方法中,这个方法是SpringBoot容器初始化并启动的核心方法。具体方法如下:
在上述代码中其实做了很多事情,例如执行SpringBoot启动时各个时机所涉及到的事件通知、创建Web容器、初始化Spring容器、初始化Spring Bean、构建嵌入式的Tomcat等等。虽然这些动作非常重要,但是这不是我们今天要讨论的重点。我们要讨论的重点是,在执行哪一行代码时,会打印出SpringBoot的LOGO?答案就是我用红框标注的printBanner()方法。如何验证呢?大家可以在这行代码进行断点调试,当这行代码执行完成后,控制台立刻会打印出我们想要看到的SpringBoot的LOGO,所以我们要对这行代码做一下深入的探究。
先看一下printBanner()方法的具体实现,具体代码如下:
这里首先会判断一下bannerMode的输出模式,这里就涉及到Banner接口的一个内部枚举类Mode,我们来看一下:
根据源代码中的注释我们可以很明确的知道,LOGO的输出分为三种模式
关闭
通过System.out输出到控制台(默认)
输出到log file中
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);
}
获取Banner接口对应实现类的对象
执行打印操作
TextBanner
ImageBanner
private Banner getImageBanner(Environment environment) {
// BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
// IMAGE_EXTENSION = { "gif", "jpg", "png" };
// 查看配置文件中是否定义了spring.banner.image.location
String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
if (StringUtils.hasLength(location)) {
// 如果有,则使用location加载资源
Resource resource = this.resourceLoader.getResource(location);
// 如果资源存在,则构建一个ImageBanner,如果不存在返回null
return resource.exists() ? new ImageBanner(resource) : null;
}
// 循环查找banner.gif/banner.jpg/banner.png三种格式的banner
for (String ext : IMAGE_EXTENSION) {
Resource resource =
this.resourceLoader.getResource("banner." + ext);
// 如果存在,则构建ImageBanner,不存在则返回null
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
private Banner getTextBanner(Environment environment) {
// BANNER_LOCATION_PROPERTY = "spring.banner.location";
// DEFAULT_BANNER_LOCATION = "banner.txt";
// 从配置文件中获取spring.banner.location的值,
// 如果没有,默认使用banner.txt
String location = environment.getProperty(
BANNER_LOCATION_PROPERTY,
DEFAULT_BANNER_LOCATION);
// 通过location加载资源
Resource resource = this.resourceLoader.getResource(location);
// 如果资源存在,则构建一个ResourceBanner对象,如果不存在,则返回空
if (resource.exists()) {
return new ResourceBanner(resource);
}
return null;
}
如果以上两种Banner都加载不到,则回去加载默认的SpringBootBanner。代码如下:
这就是我们启动时默认看到的SpringBoot的LOGO。
获取到Banner对象之后就会调用Banner接口的printBanner方法执行打印操作。这里比较简单,我就简单介绍一下。
针对ResourceBanner,会先将Banner.txt文件转成输入流对象,然后调用System.out输出到控制台。这中间会做一些渲染着色的操作。
针对ImageBanner,会先根据图片的形状大小使用特殊字符描绘出同比例的长宽高,然后再根据图片的颜色将输出字符进行着色操作并最终输出,也就是说,虽然我们在项目中放了一张图片,但是在打印时,SpringBoot并不会真正将图片渲染到控制台,而是通过字符的方式,大概描绘出所放置的图片的样式。
通过上面源代码的介绍,我们已经对原理了解的比较清楚。那么接下来定制自己的LOGO就是一件非常简单的事情了。下面我就直接说一下步骤:
在resources目录下新建banner.txt
将自定义的图案放到banner.txt中。那图案从哪里来呢?这里介绍一个非常好用的工具网站:http://patorjk.com/software/taag,在网页上可以自由定制你想要的图案(仅支持英文)。例如我输入Sugar,会出来很多风格不同的LOGO。
直接将这些图案复制到banner.txt中,就可以达到我们想要的效果。
图片LOGO:
例如下面: