banner演示
默认banner
- 什么都不用设置,直接运行
文字banner
两种方式:
- 在resource目录下 设置一个banner.txt文件
- yml文件中设置spring.banner.location值为文件路径 即可
图片banner
两种方式:
- 在resource目录下 设置一个banner.(gif | png | jpg)文件
- yml文件中设置spring.banner.image.location值为文件路径 即可
兜底banner
当没有通过以上方式进行banner配置的时候,可以定义一个兜底的banner使其生效
- 在启动类中通过 springApplication.setBanner()来进行配置
关闭banner
- 在yml配置文件中 通过设置spring.main.banner-mode=off来关闭banner设置
banner获取原理
org.springframework.boot.SpringApplication#run(java.lang.String…)
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
/*...*/
try {
/*...*/
//1
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
/*...*/
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
//1
private Banner printBanner(ConfigurableEnvironment environment) {
//与 关闭banner 一栏相对应
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
if (printBannerViaDeprecatedMethod(environment)) {
return null;
}
//获取一个ResourceLoader
ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
//1.1 构建一个SpringApplicationBannerPrinter
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
resourceLoader, this.banner);
//Mode : OFF(关闭)、CONSOLE(打印在控制台)、LOG(打印在日志中)
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
//1.2
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
//1.1
SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
this.resourceLoader = resourceLoader;
//设置兜底的banner
this.fallbackBanner = fallbackBanner;
}
//1.2
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
//1.2.1 获取banners集合
Banner banner = getBanner(environment, this.fallbackBanner);
//依次按照banners结合进行输出
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
//1.2.1 获取banners集合
private static final Banner DEFAULT_BANNER = new SpringBootBanner();
private Banner getBanner(Environment environment, Banner definedBanner) {
Banners banners = new Banners();
// 1.2.1.1 获取image banner
banners.addIfNotNull(getImageBanner(environment));
// 1.2.1.2 获取text banner
banners.addIfNotNull(getTextBanner(environment));
// 判断banners集合是否为空
if (banners.hasAtLeastOneBanner()) {
//不为空则返回
return banners;
}
//兜底banner是否为空
if (this.fallbackBanner != null) {
//不为空返回兜底banner
return this.fallbackBanner;
}
//返回 DEFAULT_BANNER
return DEFAULT_BANNER;
}
private static class Banners implements Banner {
private final List<Banner> banners = new ArrayList<Banner>();
}
// 1.2.1.1
static final String BANNER_IMAGE_LOCATION_PROPERTY = "banner.image.location";
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
private Banner getImageBanner(Environment environment) {
//获取banner.image.location的属性值
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);
}
//循环{ "gif", "jpg", "png" } 三个值
for (String ext : IMAGE_EXTENSION) {
//拼接属性字段,分别为 “banner.gif”、“banner.jpg”、“banner.png”
Resource resource = this.resourceLoader.getResource("banner." + ext);
//如果属性字段对应的值存在的话 并返回添加到调用的集合中
if (resource.exists()) {
return new ImageBanner(resource);
}
}
return null;
}
// 1.2.1.2
static final String BANNER_LOCATION_PROPERTY = "banner.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";
private Banner getTextBanner(Environment environment) {
//判断是否存在"banner.location"的属性值,否则的话 获取"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);
}
//都不存在的话 返回null
return null;
}
流程总结
- run方法体内调用 Banner printedBanner = printBanner(environment);
- 调用获取banner逻辑
- 获取banner中 调用getImageBanner方法
- 可以通过spring.banner.image.location指定位置
- 可使用图片格式
- 获取banner中 调用getTextBanner方法
- 可以通过spring.banner.location指定位置
- 默认是banner.txt
banner输出原理
入口
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
//获取的所有的banner
Banner banner = getBanner(environment, this.fallbackBanner);
//1 打印指定的banner
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
}
//1
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream out) {
//循环遍历所有的banners
for (Banner banner : this.banners) {
//1.1 打印
//三中实现,一:SpringBootBanner,二:ResourceBanner
banner.printBanner(environment, sourceClass, out);
}
}
默认输出源码
org.springframework.boot.SpringBootBanner#printBanner
//1.1 SpringBootBanner
private static final String[] BANNER = { "",
" . ____ _ __ _ _",
" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\",
"( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )",
" ' |____| .__|_| |_|_| |_\\__, | / / / /",
" =========|_|==============|___/=/_/_/_/" };
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream printStream) {
for (String line : BANNER) {
//打印banner
printStream.println(line);
}
//获取SpringBoot版本号
String version = SpringBootVersion.getVersion();
version = (version == null ? "" : " (v" + version + ")");
String padding = "";
while (padding.length() < STRAP_LINE_SIZE
- (version.length() + SPRING_BOOT.length())) {
padding += " ";
}
//输出带颜色的版本号,输出颜色字体为java自带功能,如:
// System.out.println("\u001B[32m this is spring boot");
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
printStream.println();
}
默认输出总结
- 先输出banner指定的内容
- 获取version信息
- 文本内容前后对齐
- 文本内容染色
文字banner输出源码
org.springframework.boot.ResourceBanner#printBanner
//1.1 ResourceBanner
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream out) {
try {
//将指定的路径资源 转为String字符串
String banner = StreamUtils.copyToString(this.resource.getInputStream(),
environment.getProperty("banner.charset", Charset.class,
Charset.forName("UTF-8")));
//依次使用属性编辑器 去替换占位符,即:可以通过在文本中引用#{myTest},并在yml文件中定义 myTest: bannerTest, 来实现占位符属性值填充
for (PropertyResolver resolver : getPropertyResolvers(environment,
sourceClass)) {
banner = resolver.resolvePlaceholders(banner);
}
//banner输出
out.println(banner);
}
catch (Exception ex) {
logger.warn("Banner not printable: " + this.resource + " (" + ex.getClass()
+ ": '" + ex.getMessage() + "')", ex);
}
}
文字banner输出总结
- 可以通过spring.banner.charset指定字符集
- 获取文本内容
- 替换占位符
- 输出文本内容
图片banner输出源码
org.springframework.boot.ImageBanner#printBanner(org.springframework.core.env.Environment, java.lang.Class<?>, java.io.PrintStream)
//1.1 ImageBanner
@Override
public void printBanner(Environment environment, Class<?> sourceClass,
PrintStream out) {
String headless = System.getProperty("java.awt.headless");
try {
//定义java是在没有显示器的模式下进行工作
System.setProperty("java.awt.headless", "true");
//1.1.1 进行打印
printBanner(environment, out);
}
catch (Throwable ex) {
log.warn("Image banner not printable: " + this.image + " (" + ex.getClass()
+ ": '" + ex.getMessage() + "')");
log.debug("Image banner printing failure", ex);
}
finally {
if (headless == null) {
System.clearProperty("java.awt.headless");
}
else {
System.setProperty("java.awt.headless", headless);
}
}
}
//1.1.1 进行打印
private void printBanner(Environment environment, PrintStream out)
throws IOException {
PropertyResolver properties = new RelaxedPropertyResolver(environment,
"banner.image.");
//获取宽、高、边距、是否旋转 等值,可通过banner.image.width、banner.image.height、banner.image.margin、banner.image.invert 来进行指定,否则使用默认值
int width = properties.getProperty("width", Integer.class, 76);
int height = properties.getProperty("height", Integer.class, 0);
int margin = properties.getProperty("margin", Integer.class, 2);
boolean invert = properties.getProperty("invert", Boolean.class, false);
//调用绘图jar包记性
BufferedImage image = readImage(width, height);
//打印
printBanner(image, margin, invert, out);
}
图片banner输出总结
- 可以通过spring.banner.image.*设置图片属性
- 读取图片文件流
- 输出图片内容
面试题
- 举例banner常见配置方式
- 简述下框架内banner打印流程步骤
- 说明下banner获取原理
- 说明下banner输出原理
- 说出你熟悉的banner属性有哪些