用过SpringBoot的同学都知道,在SpringBoot项目启动时,会默认打印一个"Spring"的字符,如下图所示
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.9.RELEASE)
这个被称为SpringBoot框架的banner,项目启动时会出现在很醒目的位置上,我们在开发过程中每启动一次项目,就会出现这个banner图,那么我们能不能自定义这个banner图呢?答案是可以的,下面我们一起从源码的角度看一下如何自定义这个banner
源码分析
想要了解banner的自定义规则,我们就要从程序启动的入口开始,SpringBoot一般是从如下的Main函数来启动的
@SpringBootApplication
public class Main {
public static void main(String[] args){
SpringApplication.run(Main.class, args);
}
}
可以看到main方法调用了SpringApplication的run方法用来引导启动项目,那么我们肯定要从这个run方法入手
跟源码最后可以看到在SpringApplication类中有一个可变参数的run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//这里就是打印banner的方法
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
从源码中可以看出来,SpringBoot是专门写了一个方法用来打印Banner的,如下一行代码就是用来打印banner的
Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
//可以看到banner打印是可以控制不打印的
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);
//通过参数来控制是打印在log中,还是打印在控制台
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
从源码中可以看到,可以通过参数来控制不打印Banner,默认是打印的。也可以控制banner是打印在log中还是打印在控制台
下面来看一下Banner获取规则
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);
}
private Banner getBanner(Environment environment) {
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;
}
return DEFAULT_BANNER;
}
先获取图片banner,再获取文本banner,两个可以同时配置
同时配置时会先打印图片banner,再打印文本banner
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
//获取图片banner
private Banner getImageBanner(Environment environment) {
//优先从spring.banner.image.location配置对应的地址获取banner
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;
}
//没有配置则从根目录下依次获取banner.gif、banner.jpg、banner.png
for (String ext : IMAGE_EXTENSION) {
Resource resource = this.resourceLoader.getResource("banner." + ext);
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
static final String DEFAULT_BANNER_LOCATION = "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);
if (resource.exists()) {
return new ResourceBanner(resource);
}
return null;
}
上面的代码显示了获取图片banner和文本banner的规则,可以自定义图片或文本
以上就是自定义banner的规则,知道了规则之后,我们就可以根据规则来自定义一个banner
有很多可以生成自定义banner的网站,比如https://www.bootschool.net/ascii/
.::::.
.::::::::.
:::::::::::
':::::::::::..
:::::::::::::::'
':::::::::::.
.::::::::::::::'
.:::::::::::...
::::::::::::::''
.:::. '::::::::''::::
.::::::::. ':::::' '::::
.::::':::::::. ::::: '::::.
.:::::' ':::::::::. ::::: ':::.
.:::::' ':::::::::.::::: '::.
.::::'' ':::::::::::::: '::.
.::'' ':::::::::::: :::...
..:::: ':::::::::' .:' ''''
..''''':' ':::::.'
在项目根目录下新建banner.txt,将以上字符贴进去,重新启动项目,就可以在控制台看到你自定义的banner~