介绍
接着prepareEnvironment之后继续介绍springBoot启动流程的代码,接下来看看banner的打印。
源码
private Banner printBanner(ConfigurableEnvironment environment) {
// banner模式,如果为off则不打印
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);
}
上面代码就可以看到,对于如果banner.mode设置为空的话,则不会去打印banner。但是很多小伙伴不知道这个是什么设置的。其实是在prepareEnvironment方法里,bindToSpringApplication方法去设置的。当然也可以启动时候new SpringApplication自己设置。bindToSpringApplication中会对spring.main的设置绑定到SpringApplication上去。这边需要讲到Binder这个类,由于不是主流程,后面会进行说到。这边先说下如果关闭banner打印的几种方法。
- 在配置文件中设置spring.main.banner-mode="off",这边yml需要加引号,不然会被解析成false。
- 在启动参数中设置--spring.main.banner-mode=off
-
// 创建启动类时候设置 SpringApplication app = new SpringApplication(Application.class); application.setBannerMode(Banner.Mode.OFF); app.run(args);
接着向下看,直接看控制台输出的源码,因为其实都差不多,主要就是找到banner的位置,然后打印。
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
// 寻找banner位置
Banner banner = getBanner(environment);
// 打印banner
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
上面看逻辑很清晰,找到banner,然后打印就可以了。接着看如何寻找banner
// 文本banner位置
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
// 图片banner位置
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
// 默认文本banner位置
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
// 默认图片支持格式
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private Banner getBanner(Environment environment) {
// banner的一个列表集成
Banners banners = new Banners();
// 文本banner存在加入到列表中
banners.addIfNotNull(getImageBanner(environment));
// 图片banner存在加入列表中
banners.addIfNotNull(getTextBanner(environment));
// 如果有就返回
if (banners.hasAtLeastOneBanner()) {
return banners;
}
if (this.fallbackBanner != null) {
return this.fallbackBanner;
}
// 没有就返回默认banner,springBoot自带的banner
return DEFAULT_BANNER;
}
// 寻找文本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);
if (resource.exists()) {
return new ResourceBanner(resource);
}
return null;
}
// 寻找图片banner
private Banner getImageBanner(Environment environment) {
String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
// 从配置中拿到图片banner位置信息
if (StringUtils.hasLength(location)) {
Resource resource = this.resourceLoader.getResource(location);
return (resource.exists() ? new ImageBanner(resource) : null);
}
// 配置中没有,分别查询后缀名是"gif", "jpg", "png"的banner
for (String ext : IMAGE_EXTENSION) {
Resource resource = this.resourceLoader.getResource("banner." + ext);
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
寻找banner的代码比较长,但是逻辑也比较清晰。 springBoot支持文本的banner和图片的banner,这边就是分别去查询文本的banner和图片的banner。
springBoot支持我们配置banner的位置,默认都是去从classpath中寻找。也就是在classpath中查找banner.txt,banner.jpg,banner.gif,banner.png。如果我们自定义一个文本banner,可以直接在resource下面加一个banner.txt就行了,如果是图片的话,就加一个banner.jpg或者banner.gif或者banner.png,图片和文本都加的话,也都可以去打印的。
如:
可以看到,这边打印了图片,下面还有一个Banner的文本也被打印了出来。
如果我不想把banner放在默认的resource中怎么办呢?
这就需要代码中说到的spring.banner.location和spring.banner.image.location了。
假设我想把文本banner放在resource中的config的文件夹下,那么就在配置文件中配置spring.banner.location=/config/banner.txt就可以了。同样图片位置就设置spring.banner.image.location。这里需要注意下,在自定义图片位置的时候,图片的格式不再局限于,gif,png,jpg三种了。例如我现在改成jpeg,配置文件中设置spring.banner.image.location=/config/banner.jpeg:
可以看到此时图片格式设置成jpeg一样可以打印。
当然如果不想放在resources中,放到磁盘位置也是可以的。比如现在我想设置从d盘去读取。在配置文件中配置spring.banner.location=file:d:\test\banner1.txt;file:协议前缀一定要带上。因为spring中ResourceLoader解析对于没有带协议的,先尝试通过url去获取资源,获取不到从classpath中获取。所以不加file协议的话,直接认为是url资源去获取,获取不到就从classpath获取,源码在DefaultResourceLoader中,就不展开说了(主要url构造那段我也看不懂[😂])。
上面介绍完了自定义设置banner以及banner路径的配置,如果我们什么都不设置的话,那就会调用到springBoot自己的banner了,也就是SpringBootBanner;
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 + ")");
String padding = "";
while (padding.length() < STRAP_LINE_SIZE
- (version.length() + SPRING_BOOT.length())) {
padding += " ";
}
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
printStream.println();
}
}
这里就能看到我们熟悉的banner了,就是什么都不设置的时候打印的springBoot自带的banner。
总结
这边对于springBoot的banner打印就说完了,springBoot支持文本和图片两种banner。不配置就打印springBoot自带的banner。
简单配置的话就直接在resources中放置banner.txt,banner.png,banner.gif,banner.jpg就可以了。
也可以配置spring.banner.location和spring.banner.image.location之后,就从配置的地方读取banner了。
需要注意的是图片在没有配置spring.banner.image.location时候支持png,gig,jpg三种格式。配置之后就不会限制图片格式了。