本文共 8539 字,大约阅读时间需要 28 分钟。
##Banner 的基本作用 Banner 更多地作为一种人性化的标志,例如企业的标志、某个知名产品的标志、不同环境的标志等。在Spring Boot中,Banner的设计理念强调“大道至简”,即将Banner的非功能需求和部分功能需求封装好,让用户只需按照最傻瓜的操作步骤使用即可。
每一个应用都应该有自己的Banner,独一无二的设计使其更具个性化。
Spring Boot 提供了默认的配置方式,无需修改任何代码,只需在 resources 目录下添加 banner.txt 文件即可。
文件内容如下:
.___ _ __ _ _ /\\ / ___'__ __ _ _(_)_ __ __ _ \ \ \\( ( )\___ | '_ | '_| | '_ \\/ _` | \ \ \\ \\/ ___)| |_)| | | | | || (_| | ) ) ) )' |____| .__|_| |_|_| |_\\__, | / / / /=========|_|==============|___/=/_/_/_/:: Hello World :: ${application.formatted-version} ${AnsiColor.BRIGHT_RED}:设置控制台中输出内容的颜色${application.version}:获取MANIFEST.MF文件中的版本号${application.formatted-version}:格式化后的版本信息${spring-boot.version}:Spring Boot的版本号${spring-boot.formatted-version}:格式化后的Spring Boot版本号${application.title}:应用标题所有与Banner相关的类都位于 spring-boot 包中,主要包括以下几个关键类:
Mode 枚举控制打印模式:LOG、CONSOLE、OFF。private Banner printBanner(ConfigurableEnvironment environment) { 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); if (this.bannerMode == Mode.LOG) { return bannerPrinter.print(environment, this.mainApplicationClass, logger); } return bannerPrinter.print(environment, this.mainApplicationClass, System.out);}public void setBanner(Banner banner) { this.banner = banner;}public void setBannerMode(Banner.Mode bannerMode) { this.bannerMode = bannerMode;} setBanner(Banner) 方法允许用户自定义Banner实现类,支持扩展。setBannerMode(Banner.Mode) 方法控制Banner的打印模式,默认为 CONSOLE。static final String BANNER_LOCATION_PROPERTY = "banner.location";static final String BANNER_IMAGE_LOCATION_PROPERTY = "banner.image.location";static final String DEFAULT_BANNER_LOCATION = "banner.txt";static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };private static final Banner DEFAULT_BANNER = new SpringBootBanner();private final ResourceLoader resourceLoader;private final Banner fallbackBanner;SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) { this.resourceLoader = resourceLoader; this.fallbackBanner = fallbackBanner;}public Banner print(Environment environment, Class sourceClass) { Banner banner = getBanner(environment, this.fallbackBanner); try { logger.info(createStringFromBanner(banner, environment, sourceClass)); } catch (UnsupportedEncodingException ex) { logger.warn("Failed to create String for banner", ex); } return new PrintedBanner(banner, sourceClass);}public Banner print(Environment environment, PrintStream out) { Banner banner = getBanner(environment, this.fallbackBanner); banner.printBanner(environment, sourceClass, out); return new PrintedBanner(banner, sourceClass);}private Banner getBanner(Environment environment, Banner definedBanner) { 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;}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;}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 String createStringFromBanner(Banner banner, Environment environment, Class mainApplicationClass) throws UnsupportedEncodingException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); banner.printBanner(environment, mainApplicationClass, new PrintStream(baos)); String charset = environment.getProperty("banner.charset", "UTF-8"); return baos.toString(charset);}private static class Banners implements Banner { private final List banners = new ArrayList<>(); public void addIfNotNull(Banner banner) { if (banner != null) { this.banners.add(banner); } } public boolean hasAtLeastOneBanner() { return !this.banners.isEmpty(); } @Override public void printBanner(Environment environment, Class sourceClass, PrintStream out) { for (Banner banner : this.banners) { banner.printBanner(environment, sourceClass, out); } }}private static class PrintedBanner implements Banner { private final Banner banner; private final Class sourceClass; PrintedBanner(Banner banner, Class sourceClass) { this.banner = banner; this.sourceClass = sourceClass; } @Override public void printBanner(Environment environment, Class sourceClass, PrintStream out) { sourceClass = (sourceClass == null ? this.sourceClass : sourceClass); this.banner.printBanner(environment, sourceClass, out); }} public interface Banner { void printBanner(Environment environment, Class sourceClass, PrintStream out); enum Mode { OFF, CONSOLE, LOG }} /** * 默认的Banner实现类,用于打印“Spring Boot”的图案。 */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 + ")"); String padding = ""; while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) { padding += " "; } printStream.println(AnsiOutput.toString( AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version)); printStream.println(); }} Spring Boot 的 Banner 架构设计体现了面向对象和面向切面编程的思想,通过封装和抽象将非功能需求和部分功能需求集中管理。特别值得一提的是 PrintedBanner 和 Banners 类的设计,它们通过私有静态类的方式实现了工具类的功能,充分发挥了OOP思想的优势。
技术的发展往往遵循一定的规律,从面向过程编程到面向对象编程,再到面向切面编程、面向服务编程,这些设计思想不断演化,体现了技术生产力的提升。
转载地址:http://ietfk.baihongyu.com/