SpringBoot之Banner介绍

一、Banner 介绍

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

如上图所示的,是我们每次启动 SpringBoot 项目时就会在控制器输出的内容,这个就是 Banner

1.2 banner的输出模式

* LOG:将 banner 信息输出到日志文件。
* CONSOLE:将 banner 信息输出到控制台。
* OFF:禁用 banner 的信息输出。

二、自定义 Banner

2.1 文本形式 banner

resources 目录下新建 banner.txt 文件,内容如下:

/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/

启动项目,观察控制台输出:

/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/

可以看到 Banner 样式已经改变了。

2.2 图片样式 Banner

resources下创建 banner.jpg 文件

启动项目,查看控制台输出:

          &&&&&&&&&&                                       &&                 
        &&&       :                                        &&                 
       &&*                                                 &&                 
      &&&                8888888*    :******     &&&&&&&&: &&   8888888       
      &&&      &&&&&&&& 88&    888  **     **:  &&     &&: &&  88:   .88      
       &&           && 888      88 ***      ** &&.     &&: && :8888888        
        &&&        &&&  88      88 ***     *** &&&     &&: &&  88.            
         8&&&&&&&&&&    .88888888   *********   &&&&&&&&&: &&   88888888      
             :&&.          .8&         .**         o&  &&*        .88         
                                               .&&    .&&                     
                                                 &&&&&&&             

三、修改默认文件名

bannerSpringBoot 默认名,我们也可以自定义文件名称。

3.1 通过配置文件指定文件名

# 文本形式
spring.banner.location=icon.txt
# 图片形式
spring.banner.image.location=icon.jpg    

3.2 通过代码形式指定文件名

public static void main(String[] args) {
    SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
    springApplication.setBanner(new ResourceBanner(new ClassPathResource("icon.txt")));
    springApplication.run();
}

四、修改模式

4.1 通过配置文件修改模式

spring.main.banner-mode=off

4.2 通过代码形式修改模式

public static void main(String[] args) {
    SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
    springApplication.setBannerMode(Banner.Mode.LOG);
    springApplication.run();
}

五、Banner 输出原理

进入 run 方法:发现有个 printBanner 方法:

public ConfigurableApplicationContext run(String... args) {
    ......
    try{
        ......
        Banner printedBanner = printBanner(environment);
        ......
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);    
        ......    
    }catch (Throwable ex) {
        ......
    }   
    
}    

我们看下它的实现:

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);
    // 判断将 banner 输出到日志还是控制台
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

进入 print 方法:

Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
    // 获取 banner
    Banner banner = getBanner(environment);
    // 打印 banner
    banner.printBanner(environment, sourceClass, out);
    return new PrintedBanner(banner, sourceClass);
}

进入 getBanner 方法:

private Banner getBanner(Environment environment) {
    Banners banners = new Banners();
    // 获取图片 banner
    banners.addIfNotNull(getImageBanner(environment));
    // 获取文本 banner
    banners.addIfNotNull(getTextBanner(environment));
    // 判断是否存在一个 banner
    if (banners.hasAtLeastOneBanner()) {
        return banners;
    } 
    // 后备 banner
    if (this.fallbackBanner != null) {
        return this.fallbackBanner;
    }
    // 默认 banner
    return DEFAULT_BANNER;
}

查看两个获取 Banne 的方法

// 默认文件名
static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
// 默认图片名
static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";

private Banner getImageBanner(Environment environment) {
    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;
    }
    for (String ext : IMAGE_EXTENSION) {
        Resource resource = this.resourceLoader.getResource("banner." + ext);
        if (resource.exists()) {
            return new ImageBanner(resource);
        }
    }
    return null;
}

private Banner getTextBanner(Environment environment) {
    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;
}   

图片打印实现类 ImageBanner

@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
    String headless = System.getProperty("java.awt.headless");
    try {
        System.setProperty("java.awt.headless", "true");
        printBanner(environment, out);
    }
    catch (Throwable ex) {
        logger.warn(LogMessage.format("Image banner not printable: %s (%s: '%s')", this.image, ex.getClass(),
                ex.getMessage()));
        logger.debug("Image banner printing failure", ex);
    }
    finally {
        if (headless == null) {
            System.clearProperty("java.awt.headless");
        }
        else {
            System.setProperty("java.awt.headless", headless);
        }
    }
}

private void printBanner(Environment environment, PrintStream out) throws IOException {
    int width = getProperty(environment, "width", Integer.class, 76);
    int height = getProperty(environment, "height", Integer.class, 0);
    int margin = getProperty(environment, "margin", Integer.class, 2);
    boolean invert = getProperty(environment, "invert", Boolean.class, false);
    BitDepth bitDepth = getBitDepthProperty(environment);
    PixelMode pixelMode = getPixelModeProperty(environment);
    Frame[] frames = readFrames(width, height);
    for (int i = 0; i < frames.length; i++) {
        if (i > 0) {
            resetCursor(frames[i - 1].getImage(), out);
        }
        printBanner(frames[i].getImage(), margin, invert, bitDepth, pixelMode, out);
        sleep(frames[i].getDelayTime());
    }
}

重点关注 readFrames 方法:

private Frame[] readFrames(int width, int height) throws IOException {
    try (InputStream inputStream = this.image.getInputStream()) {
        try (ImageInputStream imageStream = ImageIO.createImageInputStream(inputStream)) {
            return readFrames(width, height, imageStream);
        }
    }
}
private Frame[] readFrames(int width, int height, ImageInputStream stream) throws IOException {
    Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
    Assert.state(readers.hasNext(), "Unable to read image banner source");
    ImageReader reader = readers.next();
    try {
        ImageReadParam readParam = reader.getDefaultReadParam();
        reader.setInput(stream);
        int frameCount = reader.getNumImages(true);
        Frame[] frames = new Frame[frameCount];
        for (int i = 0; i < frameCount; i++) {
            frames[i] = readFrame(width, height, reader, i, readParam);
        }
        return frames;
    }
    finally {
        reader.dispose();
    }
}   

六、推荐在线制作 banner 的网站

传送门

优点:

  • 切换字体以及输入文字的时候, 会自动输出 banner 字样。
  • 在输出框中,是可编辑的,可以自己添加版本号,作者简介信息等。

缺点:

  • 不能下载 txt。
  • 结果内容只有选中后,手动复制粘贴到 banner.txt 文件中。

猜你喜欢

转载自www.cnblogs.com/markLogZhu/p/12508463.html