保定网站seo,wordpress html生成app,品牌网站建设报价表,做网站用小动画SpringBoot源码系列文章
SpringBoot源码解析(一)#xff1a;SpringApplication构造方法
SpringBoot源码解析(二)#xff1a;引导上下文DefaultBootstrapContext
SpringBoot源码解析(三)#xff1a;启动开始阶段
SpringBoot源码解析(四)#xff1a;解析应用参数args
Sp…SpringBoot源码系列文章
SpringBoot源码解析(一)SpringApplication构造方法
SpringBoot源码解析(二)引导上下文DefaultBootstrapContext
SpringBoot源码解析(三)启动开始阶段
SpringBoot源码解析(四)解析应用参数args
SpringBoot源码解析(五)准备应用环境
SpringBoot源码解析(六)打印Banner 目录 前言一、入口二、Banner接口类1、打印Banner开关 三、打印Banner过程1、console和log模式2、四种Banner对象2.1、图片Banner2.2、文字Banner2.2、备用Banner2.3、默认Banner 总结 前言 在前文中我们深入解析了SpringBoot启动时应用环境的准备过程。接下来将深入介绍启动Banner打印的具体实现及流程。 SpringBoot版本2.7.18SpringApplication的run方法的执行逻辑如下本文将详细介绍第5小节打印启动Banner // SpringApplication类方法
public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间long startTime System.nanoTime();// 1.创建引导上下文用于管理应用启动时的依赖和资源DefaultBootstrapContext bootstrapContext createBootstrapContext();ConfigurableApplicationContext context null;// 配置无头模式属性以支持在无图形环境下运行// 将系统属性 java.awt.headless 设置为 trueconfigureHeadlessProperty();// 2.获取Spring应用启动监听器用于在应用启动的各个阶段执行自定义逻辑SpringApplicationRunListeners listeners getRunListeners(args);// 启动开始方法发布开始事件、通知应用监听器ApplicationListenerlisteners.starting(bootstrapContext, this.mainApplicationClass);try {// 3.解析应用参数ApplicationArguments applicationArguments new DefaultApplicationArguments(args);// 4.准备应用环境包括读取配置文件和设置环境变量ConfigurableEnvironment environment prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置是否忽略 BeanInfo以加快启动速度configureIgnoreBeanInfo(environment);// 5.打印启动BannerBanner printedBanner printBanner(environment);// 6.创建应用程序上下文context createApplicationContext();// 设置应用启动的上下文用于监控和管理启动过程context.setApplicationStartup(this.applicationStartup);// 7.准备应用上下文包括加载配置、添加 Bean 等prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 8.刷新上下文完成 Bean 的加载和依赖注入refreshContext(context);// 9.刷新后的一些操作如事件发布等afterRefresh(context, applicationArguments);// 计算启动应用程序的时间并记录日志Duration timeTakenToStartup Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 10.通知监听器应用启动完成listeners.started(context, timeTakenToStartup);// 11.调用应用程序中的 CommandLineRunner 或 ApplicationRunner以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch (Throwable ex) {// 12.处理启动过程中发生的异常并通知监听器handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 13.计算应用启动完成至准备就绪的时间并通知监听器Duration timeTakenToReady Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 处理准备就绪过程中发生的异常handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;
}一、入口
// 5.打印启动Banner
Banner printedBanner printBanner(environment);// 打印启动 Banner 的方法根据配置的 Banner 模式选择打印方式
private Banner printBanner(ConfigurableEnvironment environment) {// 如果 Banner 模式被设置为 OFF则不打印 Banner直接返回 nullif (this.bannerMode Banner.Mode.OFF) {return null;}// 确定资源加载器。如果当前实例的 resourceLoader 不为空则使用它否则创建一个默认的资源加载器ResourceLoader resourceLoader (this.resourceLoader ! null) ? this.resourceLoader: new DefaultResourceLoader(null);// 创建 Banner 打印器负责加载和打印 BannerSpringApplicationBannerPrinter bannerPrinter new SpringApplicationBannerPrinter(resourceLoader, this.banner);// 根据 Banner 模式决定打印到日志还是控制台if (this.bannerMode Mode.LOG) {// 如果 Banner 模式为 LOG则将 Banner 打印到日志中return bannerPrinter.print(environment, this.mainApplicationClass, logger);}// 默认情况下CONSOLE 模式将 Banner 打印到标准输出控制台return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}二、Banner接口类
// 一个用于以编程方式输出 Banner 的接口类
FunctionalInterface
public interface Banner {// 将 Banner 输出到指定的打印流void printBanner(Environment environment, Class? sourceClass, PrintStream out);// 用于配置 Banner 的模式枚举enum Mode {// 禁用 Banner 的打印OFF,// 将 Banner 输出到 System.outCONSOLE,// 将 Banner 输出到日志文件LOG}
}1、打印Banner开关
默认情况是打印到控制台 可以通过properties或yml设置关闭打印Banner
spring.main.banner-modeoff上一节有讲spring.main开头的属性会绑定到SpringApplication对象上这样就可以通过配置文件的属性来决定Banner的打印模式。
三、打印Banner过程
1、console和log模式
console控制台模式默认设置
// SpringApplicationBannerPrinter类方法
Banner print(Environment environment, Class? sourceClass, PrintStream out) {// 根据提供的环境信息获取横幅。Banner banner getBanner(environment);// 将横幅打印到指定的输出流中。banner.printBanner(environment, sourceClass, out);// 返回一个 PrintedBanner 对象包含打印的横幅和源类信息。return new PrintedBanner(banner, sourceClass);
}log日志文件模式通过在配置文件中设置spring.main.banner-modelog可以将应用启动Banner输出到日志文件中
// SpringApplicationBannerPrinter类方法
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);}// 返回一个 PrintedBanner 对象包含打印的横幅和源类信息。return new PrintedBanner(banner, sourceClass);
}log模式就是获取打印流内容转换为字符串然后由log日志打印罢了 两种方式都会返回一个PrintedBanner对象主要是为以后在应用上下文中注册为Bean或供其他组件使用做准备。
2、四种Banner对象
图片和文本横幅组合的Banners备用Banner默认Banner
// SpringApplicationBannerPrinter类方法// 默认Banner
private static final Banner DEFAULT_BANNER new SpringBootBanner();// 根据当前环境获取适当的横幅Banner
private Banner getBanner(Environment environment) {// 创建一个 Banners 对象用于存储图片和文本横幅Banners banners new Banners();// 尝试获取图片横幅并将其添加到 Banners 中如果非空banners.addIfNotNull(getImageBanner(environment));// 尝试获取文本横幅并将其添加到 Banners 中如果非空banners.addIfNotNull(getTextBanner(environment));// 如果至少包含一个横幅则返回组合的 Banners 对象if (banners.hasAtLeastOneBanner()) {return banners;}// 如果没有任何横幅但存在备用横幅则返回备用横幅if (this.fallbackBanner ! null) {return this.fallbackBanner;}// 如果没有任何横幅则返回默认横幅// Banner DEFAULT_BANNER new SpringBootBanner();return DEFAULT_BANNER;
}Banners对象内部持有多个Banner实现类遍历调用Banner的printBanner方法 2.1、图片Banner
尝试根据环境信息获取图片横幅Image Banner环境变量spring.banner.image.location用于指定图片路径如果未设置则默认加载路径为banner.gif、banner.jpg或banner.png按顺序查找。
private Banner getImageBanner(Environment environment) {// 从环境变量中获取横幅图片的路径// String BANNER_IMAGE_LOCATION_PROPERTY spring.banner.image.location;String location environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);// 如果路径不为空尝试加载对应的资源if (StringUtils.hasLength(location)) {Resource resource this.resourceLoader.getResource(location);// 如果资源存在返回对应的 ImageBanner 对象return resource.exists() ? new ImageBanner(resource) : null;}// 如果未指定路径尝试加载默认图片横幅文件// String[] IMAGE_EXTENSION { gif, jpg, png };for (String ext : IMAGE_EXTENSION) {Resource resource this.resourceLoader.getResource(banner. ext);// 如果找到存在的文件资源返回对应的 ImageBanner 对象if (resource.exists()) {return new ImageBanner(resource);}}// 如果没有找到任何图片横幅资源返回 nullreturn null;
}控制台效果 2.2、文字Banner
尝试根据环境信息获取文本横幅Text Banner环境变量spring.banner.location用于指定文本路径如果未设置则默认加载路径为banner.txt。
private Banner getTextBanner(Environment environment) {// 获取横幅的路径优先使用环境变量中的配置如果没有配置则使用默认路径// String BANNER_LOCATION_PROPERTY spring.banner.location;// String DEFAULT_BANNER_LOCATION banner.txt;String location environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);// 使用 ResourceLoader 加载指定路径的资源Resource resource this.resourceLoader.getResource(location);try {// 检查资源是否存在且路径中不包含 liquibase-core防止加载到不相关的资源if (resource.exists() !resource.getURL().toExternalForm().contains(liquibase-core)) {// 如果资源有效返回对应的 ResourceBanner 对象return new ResourceBanner(resource);}} catch (IOException ex) {// 忽略异常可能是资源加载时出错或路径无效// 在这里不抛出异常而是返回 null表示没有有效的横幅资源}// 如果资源无效或发生异常返回 nullreturn null;
}控制台效果 2.2、备用Banner SpringApplicationBannerPrinter对象的备用Banner属性fallbackBanner是由SpringApplication对象的私有属性banner传递而来的。 可以在SpringBoot启动类中通过调用SpringApplication的setBanner方法直接设置自定义的Banner对象
SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication app new SpringApplication(Application.class);// 设置全局备用横幅app.setBanner((environment, sourceClass, out) - {out.println( 全局备用横幅 );out.println( 默认横幅已启用 );out.println();});app.run(args);}
}控制台效果 2.3、默认Banner 如果未设置自定义文字图片Banner或备用BannerSpringBoot将使用默认的启动横幅SpringBootBanner作为显示内容。
// 默认的 Banner 实现用于打印 Spring 的启动横幅和版本信息
class SpringBootBanner implements Banner {// 预定义的 ASCII 艺术横幅每行为一个数组元素private static final String[] BANNER { , . ____ _ __ _ _, /\\\\ / ____ __ _ _(_)_ __ __ _ \\ \\ \\ \\,( ( )\\___ | _ | _| | _ \\/ _ | \\ \\ \\ \\, \\\\/ ___)| |_)| | | | | || (_| | ) ) ) ), |____| .__|_| |_|_| |_\\__, | / / / /, |_||___//_/_/_/ };// 固定的 Spring Boot 标识符用于横幅输出private static final String SPRING_BOOT :: Spring Boot :: ;// 横幅固定宽度用于计算 padding 的空格数private static final int STRAP_LINE_SIZE 42;/*** 输出横幅到指定的 PrintStream如控制台或日志。*/Overridepublic void printBanner(Environment environment, Class? sourceClass, PrintStream printStream) {// 遍历并打印每一行 ASCII 艺术横幅for (String line : BANNER) {printStream.println(line);}// 获取 Spring Boot 的版本信息String version SpringBootVersion.getVersion();// 如果版本信息不为空则格式化为 (vX.X.X)version (version ! null) ? (v version ) : ;// 构造 padding 空格使横幅版本号对齐StringBuilder padding new StringBuilder();while (padding.length() STRAP_LINE_SIZE - (version.length() SPRING_BOOT.length())) {padding.append( );}// 打印 Spring Boot 标识符和版本信息使用 ANSI 输出样式printStream.println(AnsiOutput.toString(AnsiColor.GREEN, // 绿色输出 Spring Boot 标识符SPRING_BOOT, AnsiColor.DEFAULT, // 恢复默认颜色padding.toString(), // 填充的空格AnsiStyle.FAINT, // 微弱样式淡化显示版本信息version // 版本号));// 添加空行用于分隔横幅和其他输出printStream.println();}
}控制台效果 总结 本文全面解析了SpringBoot启动横幅的实现原理、打印流程及自定义方法介绍了文本横幅默认路径为banner.txt可通过spring.banner.location配置、图片横幅默认路径为banner.gif、banner.jpg或banner.png可通过spring.banner.image.location配置、备用横幅和默认横幅的使用帮助开发者灵活运用横幅机制提升项目启动体验。