美文网首页
手撕SpringBoot源码---启动时如何自定义Banner

手撕SpringBoot源码---启动时如何自定义Banner

作者: Felix_ | 来源:发表于2021-11-07 11:09 被阅读0次

SpringBoot启动之后,默认会打印SpringBootBanner,想要修改它,网上有很多的文章介绍,只要在resources中添加定义的banner.txt或者banner.png等都可以,但是他是怎么样的一个加载过程呢,我们来看下SpringBoot启动之后,对于Banner的处理,常见入口函数如下

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

在调用SpringApplicationrun方法之后

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        ConfigurableApplicationContext context = null;
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            prepareContext(bootstrapContext, 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, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

这里有个专门用于输出banner的方法printBanner(environment)

    private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
                : new DefaultResourceLoader(null);
        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);
    }

在此处可以看到,如果我们没有定义resourceLoader,那么就会采用默认的DefaultResourceLoader来加载资源。同时,会创建一个SpringApplicationBannerPrinter来进行banner输出,默认的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();

如果我们在resources中指定了banner.txt或者图片类型的banner,那么就会从resources中加载,否则就会采用默认的SpringBootBanner

    private Banner getBanner(Environment environment) {
        Banners banners = new Banners();
        banners.addIfNotNull(getImageBanner(environment));
        banners.addIfNotNull(getTextBanner(environment));
        if (banners.hasAtLeastOneBanner()) {
            return banners;
        }
        if (this.fallbackBanner != null) {
            return this.fallbackBanner;
        }
        return DEFAULT_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 + ")" : "";
        StringBuilder padding = new StringBuilder();
        while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
            padding.append(" ");
        }

        printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
                AnsiStyle.FAINT, version));
        printStream.println();
    }

}

是不是很熟悉,当然,知道了原理,那么要修改它就很简单了,我们可以直接指定banner.txt,也可以指定ResourceBanner从我们希望的地方加载banner,比如直接从网络图片来加载

public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(DemoApplication.class);
        try {
            ImageBanner imageBanner = new ImageBanner(new UrlResource("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201511%2F03%2F20151103192514_JMKza.thumb.400_0.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1638846183&t=c62cdc650738467a80c637a5dc8a33e1"));
            springApplication.setBanner(imageBanner);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        springApplication.run(args);
    }

启动效果如图


image.png

当然,也可以直接使用指定的字符串

public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(DemoApplication.class);
        try {
            String felix = "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "FFFFFFFFFFFFFFFFFFFFFF     EEEEEEEEEEEEEEEEEEEEEE     LLLLLLLLLLL                  IIIIIIIIII     XXXXXXX       XXXXXXX\n" +
                    "F::::::::::::::::::::F     E::::::::::::::::::::E     L:::::::::L                  I::::::::I     X:::::X       X:::::X\n" +
                    "F::::::::::::::::::::F     E::::::::::::::::::::E     L:::::::::L                  I::::::::I     X:::::X       X:::::X\n" +
                    "FF::::::FFFFFFFFF::::F     EE::::::EEEEEEEEE::::E     LL:::::::LL                  II::::::II     X::::::X     X::::::X\n" +
                    "  F:::::F       FFFFFF       E:::::E       EEEEEE       L:::::L                      I::::I       XXX:::::X   X:::::XXX\n" +
                    "  F:::::F                    E:::::E                    L:::::L                      I::::I          X:::::X X:::::X   \n" +
                    "  F::::::FFFFFFFFFF          E::::::EEEEEEEEEE          L:::::L                      I::::I           X:::::X:::::X    \n" +
                    "  F:::::::::::::::F          E:::::::::::::::E          L:::::L                      I::::I            X:::::::::X     \n" +
                    "  F:::::::::::::::F          E:::::::::::::::E          L:::::L                      I::::I            X:::::::::X     \n" +
                    "  F::::::FFFFFFFFFF          E::::::EEEEEEEEEE          L:::::L                      I::::I           X:::::X:::::X    \n" +
                    "  F:::::F                    E:::::E                    L:::::L                      I::::I          X:::::X X:::::X   \n" +
                    "  F:::::F                    E:::::E       EEEEEE       L:::::L         LLLLLL       I::::I       XXX:::::X   X:::::XXX\n" +
                    "FF:::::::FF                EE::::::EEEEEEEE:::::E     LL:::::::LLLLLLLLL:::::L     II::::::II     X::::::X     X::::::X\n" +
                    "F::::::::FF                E::::::::::::::::::::E     L::::::::::::::::::::::L     I::::::::I     X:::::X       X:::::X\n" +
                    "F::::::::FF                E::::::::::::::::::::E     L::::::::::::::::::::::L     I::::::::I     X:::::X       X:::::X\n" +
                    "FFFFFFFFFFF                EEEEEEEEEEEEEEEEEEEEEE     LLLLLLLLLLLLLLLLLLLLLLLL     IIIIIIIIII     XXXXXXX       XXXXXXX\n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       \n" +
                    "                                                                                                                       ";

            ResourceBanner resourceBanner = new ResourceBanner(new ByteArrayResource(felix.getBytes()));
            springApplication.setBanner(resourceBanner);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        springApplication.run(args);
    }

执行效果如图

image.png
最后就是网上常见的方案了,直接放置一个banner.txt,然后SpringBoot启动之后就会自动加载了,这中方案网上很多,就不再介绍了。

相关文章

网友评论

      本文标题:手撕SpringBoot源码---启动时如何自定义Banner

      本文链接:https://www.haomeiwen.com/subject/ltfezltx.html