SpringBoot趣探究--1.logo是如何打印出来的

一.前言

 从本篇开始,我将对springboot框架做一个有趣的探究,探究一下它的流程,虽然源码看不懂,不过我们可以一点一点慢慢深挖,好了,下面我们来看一下本篇的知识,这个logo是如何打印出来的?

二.分析

  springboot在启动的时候会打印一个spring的logo以及对应的版本等信息,下面我们看一下这个是如何打印的?

 我们先新建一个springboot空项目,然后我们先看一下启动类:

很平常的一个启动类,那么他是如何打印的呢?看到这里有个run方法,既然run方法能启动项目,那么run方法里面肯定调用了main()方法,我们点进去看一下这个SpringApplication类:

 

好家伙,这么多属性,别急,我们先先看一下,我们发现他第一个属性是个字符串叫banner.txt,这时我突然想到之前学修改springboot启动Logo时,只需要在resoures目录下创建一个banner.txt文件,然后写入我们的Logo,那么它就会变成我们的logo,是不是这样呢?我们先试一下:

在resources目录下创建banner.txt文件,然后写入:

 

随便一个文字型的logo,然后我们启动项目:

 

看到了我们的springlogo变成了我们自己的logo,好,那么为什么默认是spring的logo呢?

继续看一下,有哪些方法或者属性:

 

  我们发现这个类中还有一个Banner类的成员变量,我们点进去看一下:

 

@FunctionalInterface
public interface Banner {
    void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);

    public static enum Mode {
        OFF,
        CONSOLE,
        LOG;

        private Mode() {
        }
    }
}

发现它是一个接口,有一个默认的printBanner方法,不过既然是接口,那么我们需要去找它的实现类,我们看一下它有哪些实现类?

可以看到,它有五个实现类,还有ImageBanner这个,这个应该是打印图片Logo的,还有 

我们看他最后一个SpringBootBanner类,点进去看一下:

 

class SpringBootBanner implements Banner {
    private static final String[] BANNER = new String[]{"", "  .   ____          _            __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /", " =========|_|==============|___/=/_/_/_/"};
    private static final String SPRING_BOOT = " :: Spring Boot :: ";
    private static final int STRAP_LINE_SIZE = 42;

    SpringBootBanner() {
    }

    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
        String[] var4 = BANNER;
        int var5 = var4.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String line = var4[var6];
            printStream.println(line);
        }

        String version = SpringBootVersion.getVersion();
        version = version != null ? " (v" + version + ")" : "";
        StringBuilder padding = new StringBuilder();

        while(padding.length() < 42 - (version.length() + " :: Spring Boot :: ".length())) {
            padding.append(" ");
        }

        printStream.println(AnsiOutput.toString(new Object[]{AnsiColor.GREEN, " :: Spring Boot :: ", AnsiColor.DEFAULT, padding.toString(), AnsiStyle.FAINT, version}));
        printStream.println();
    }
}

我们发现,它有一个final的String数组,里面有一些字符,然后它的printBanner方法里面的while循环里面还有好像是打印::Spring Boot::的代码,现在我们可以确定,它是吧图标写在数组里面的,然后直接打印这个数组了,不信的话,吧这个类单独拿出来,测试一下:

@SpringBootTest
class StudyAutoConfigurationApplicationTests {

    private static final String[] BANNER = new String[]{"", "  .   ____          _            __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /", " =========|_|==============|___/=/_/_/_/"};
    private static final String SPRING_BOOT = " :: Spring Boot :: ";
    private static final int STRAP_LINE_SIZE = 42;


    @Test
    void contextLoads() throws IOException {

        printBanner();
    }
        public void printBanner() throws IOException {

           // PrintStream printStream = new PrintStream(Files.newOutputStream(Paths.get("a.txt")));


            String[] var4 = BANNER;
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String line = var4[var6];
                System.out.println(line);
            }

            String version = SpringBootVersion.getVersion();
            version = " (v" + version + ")";
            StringBuilder padding = new StringBuilder();

            while(padding.length() < 42 - (version.length() + " :: Spring Boot :: ".length())) {
                padding.append(" ");
            }

            System.out.println(AnsiOutput.toString(AnsiColor.GREEN, " :: Spring Boot :: ", AnsiColor.DEFAULT, padding.toString(), AnsiStyle.FAINT, version));
            System.out.println();
        }

}

我们在springboot的测试类中封装这些属性和方法,然后我们测试一下:

可以看到,成功的打印出来了logo,这样就解决了心中的疑惑, 

不过之前我们还看到有一个ImageBanner类,这个应该是打印图片的,我们先看一下:

public class ImageBanner implements Banner {
    private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
    private static final String PROPERTY_PREFIX = "spring.banner.image.";
    private static final Log logger = LogFactory.getLog(ImageBanner.class);
    private static final double[] RGB_WEIGHT = new double[]{0.2126, 0.7152, 0.0722};
    private final Resource image;

    public ImageBanner(Resource image) {
        Assert.notNull(image, "Image must not be null");
        Assert.isTrue(image.exists(), "Image must exist");
        this.image = image;
    }

 可以看到它好像需要一个java.awt.headless还有一个spring.banner.image.前缀的文件,看一下他的printBanner方法:


    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
        try {
            if (System.getProperty("java.awt.headless") == null) {
                System.setProperty("java.awt.headless", "true");
            }

            this.printBanner(environment, out);
        } catch (Throwable var5) {
            logger.warn(LogMessage.format("Image banner not printable: %s (%s: '%s')", this.image, var5.getClass(), var5.getMessage()));
            logger.debug("Image banner printing failure", var5);
        }

    }

    private void printBanner(Environment environment, PrintStream out) throws IOException {
        int width = (Integer)this.getProperty(environment, "width", Integer.class, 76);
        int height = (Integer)this.getProperty(environment, "height", Integer.class, 0);
        int margin = (Integer)this.getProperty(environment, "margin", Integer.class, 2);
        boolean invert = (Boolean)this.getProperty(environment, "invert", Boolean.class, false);
        AnsiColors.BitDepth bitDepth = this.getBitDepthProperty(environment);
        PixelMode pixelMode = this.getPixelModeProperty(environment);
        Frame[] frames = this.readFrames(width, height);

        for(int i = 0; i < frames.length; ++i) {
            if (i > 0) {
                this.resetCursor(frames[i - 1].getImage(), out);
            }

            this.printBanner(frames[i].getImage(), margin, invert, bitDepth, pixelMode, out);
            this.sleep(frames[i].getDelayTime());
        }

    }

 可以看到,读取了宽度,高度,margin,invert等属性,不过控制台应该没法演示,它应该是Java的图形化编程用的,awt

好了,以上就是对springboot的logo原理分析了,这也是作为springboot系列文章的开端,希望以后能带来更多好玩有趣的知识!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/173490.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu设设置默认外放和麦克风设备

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pulseaudio 是什么&#xff1f;二、配置外放1.查看所有的外放设备2.设定默认的外放设备3.设定外放设备的声音强度4.设定外放设备静音 三、配置麦克风1.查看…

做好性能测试计划的4个步骤!全都是精华!【建议收藏】

如何做好一次性能测试计划呢&#xff1f;对于性能测试新手来说&#xff0c;也许你非常熟悉Jmeter的使用&#xff0c;也许你清楚的了解每一个系统参数代表的意义&#xff0c;但是想要完成好一次性能测试任务&#xff0c;并不仅仅是简单的写脚本&#xff0c;加压力&#xff0c;再…

育种值探秘丨动植物遗传育种

育种值&#xff1a;生物的数字密码 嗨&#xff0c;大家好&#xff01;今天分享的笔记是遗传育种领域中那神秘莫测的育种值。这个抽象的名词具体如何理解&#xff1f;为什么说育种值很重要&#xff1f;具体怎么计算&#xff1f;有什么用处&#xff1f; 别担心&#xff0c;我会用…

万字解析设计模式之桥接模式、外观模式

一、桥接模式 1.1概述 桥接模式是一种结构型设计模式&#xff0c;它的作用是将抽象部分和实现部分分离开来&#xff0c;使它们能够独立地变化。这样&#xff0c;抽象部分和实现部分可以分别进行扩展&#xff0c;而不会相互影响。它是用组合关系代替继承关系来实现&#xff0c;…

Linux:wget后台下载/查看后台任务进度

1. 后台下载 使用wget -b url&#xff1a; wget -b http://cn.wordpress.org/wordpress-3.1-zh_CN.zip后台任务启动后&#xff0c;会返回两段话&#xff0c;第一段返回一个pid&#xff0c;代表这个后台任务的进程&#xff0c;并且我们可以kill掉这个id来终止此次下载&#x…

【Python】给出n个数,找出这n个数的最大值,最小值,和。

问题描述 给出n个数&#xff0c;找出这n个数的最大值&#xff0c;最小值&#xff0c;和。 样例输入 5 1 3 -2 4 5 Data 样例输出 5 -2 11 n int(input()) # 从用户输入中读取一个整数&#xff0c;将其赋给变量n# 从用户输入中读取一行字符串&#xff0c;使用空格分割字符串&a…

LED Driver数码屏应用解决方案

今天给大家介绍的产品是LED Driver&#xff0c;这属于电源管理类芯片&#xff0c;一般分为恒流驱动与恒压驱动&#xff0c;但是常见的就是恒流驱动&#xff0c;能够保持产品在驱动中提供恒定且稳定的电流。 基本概述 TM1629是一种带键盘扫描接口的LED&#xff08;发光二极管显…

线程池[重点]

线程池概述 线程池就是一个可以复用线程的技术。 不使用线程池的问题 &#xff1a;如果用户每发起一个请求&#xff0c;后台就创建一个新线程来处理&#xff0c;下次新任务来了又要创建新线程&#xff0c;而创建新线程的开销是很大的&#xff0c;这样会严重影响系统的性能。 …

2023年中国醇酸树脂涂料需求量、应用领域及市场规模前景分析[图]

醇酸树脂指多元醇和多元酸与脂肪酸经过酯化缩聚生成的高聚物&#xff0c;其由邻苯二甲酸酐、多元醇和脂肪酸或甘油三脂肪酸酯缩合聚合而成。醇酸树脂固化成膜后&#xff0c;具有耐磨性好、绝缘性佳等优势&#xff0c;在涂料领域应用广泛。2022年醇酸树脂产量约336.3万吨&#x…

完全二叉树你需要了解一下

完全二叉树介绍完全二叉树应用场景完全二叉树和满二叉树的区别完全二叉树代码示例拓展 完全二叉树介绍 完全二叉树&#xff08;Complete Binary Tree&#xff09;是一种特殊的二叉树&#xff0c;它的定义是&#xff1a;如果设二叉树的深度为h&#xff0c;除第h层外&#xff0c…

基于白冠鸡算法优化概率神经网络PNN的分类预测 - 附代码

基于白冠鸡算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于白冠鸡算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于白冠鸡优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

改进YOLOv8:结合Biformer——基于动态稀疏注意力构建高效金字塔网络架构

🗝️YOLOv8实战宝典--星级指南:从入门到精通,您不可错过的技巧   -- 聚焦于YOLO的 最新版本, 对颈部网络改进、添加局部注意力、增加检测头部,实测涨点 💡 深入浅出YOLOv8:我的专业笔记与技术总结   -- YOLOv8轻松上手, 适用技术小白,文章代码齐全,仅需 …

为什么AirtestIDE的selenium Window突然无法检索控件了?

1. 前言 最近有很多朋友跟我们反馈&#xff0c;为什么1.2.15版本的IDE没办法做网页元素检索了&#xff0c;是不是我们不支持selenium了之类的。 测试后发现&#xff0c;目前版本确实存在这个问题&#xff0c;原因是Chrome113.0.5672.127(最新)版本过高&#xff0c;AirtestIDE…

C语言--输入三角形的三边,输出三角形的面积

一.题目描述 输入三角形的三边&#xff0c;输出三角形的面积。比如&#xff1a;输入三角形的三边长度是3&#xff0c;4&#xff0c;5.输出6 二.思路分析 利用海伦公式可以很好解决 海伦公式的表达式如下&#xff1a; s (a b c) / 2 面积 sqrt((s * (s - a) * (s - b) * (…

基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度matlab程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 参考文献&#xff1a; 基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度——陈登勇 主要内容&#xff1a; 以碳交易和碳封存成本、燃煤机组启停和煤耗成本、弃风成本、购气成本之和为目标函数&…

安装gitlab

安装gitlab 环境 关闭防火墙以及selinux&#xff0c;起码4核8G 内存至少 3G 不然启动不了 下载环境 gitlab官网&#xff1a;GitLab下载安装_GitLab最新中文基础版下载安装-极狐GitLab rpm包下载地址&#xff1a; [Yum - Nexus Repository Manager (gitlab.cn)](https://pack…

使用 ClickHouse 做日志分析

原作&#xff1a;Monika Singh & Pradeep Chhetri 这是我们在 Monitorama 2022 上发表的演讲的改编稿。您可以在此处找到包含演讲者笔记的幻灯片和此处的视频。 当 Cloudflare 的请求抛出错误时&#xff0c;信息会记录在我们的 requests_error 管道中。错误日志用于帮助解…

【Spring Boot】如何运用Spring Cache并设置缓存失效时间

简单描述 Spring Cache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。Spring Cache提供了一层抽象&#xff0c;底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheMan…

Arduino驱动Si7021温湿度传感器(温湿度传感器)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 Si7021温湿度传感器,应用了专用的数字模块采集技术和温湿度传感技术,具有极高的可靠性与卓越的长期稳定性。同时其体积小巧、精度高,特别是拥有毫秒级测试转换时间(DHT系列需要约2s的转换时间),启动测量与读…

【LeetCode刷题】--12.整数转罗马数字

12.整数转罗马数字 方法&#xff1a;模拟 分析罗马数字的规则是&#xff1a;对于罗马数字从左到右的每一位&#xff0c;选择尽可能大的符号值 根据罗马数字的唯一表示法&#xff0c;为了表示一个给定的整数num&#xff0c;寻找不超过num的最大符号值&#xff0c;将num减去该符…