banner解析

本文详细解析了Spring Boot中Banner的配置方式,包括默认文本、图片及关闭Banner的方法。同时,深入介绍了Banner的获取和输出流程,包括从资源文件加载、属性占位符替换到不同类型的Banner(文本、图片)处理。最后,文中还提供了面试相关的知识点,如Banner的常见配置、打印流程、获取原理和输出原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

banner演示

默认banner

  • 什么都不用设置,直接运行

文字banner

两种方式:

  1. 在resource目录下 设置一个banner.txt文件
  2. yml文件中设置spring.banner.location值为文件路径 即可

图片banner

两种方式:

  1. 在resource目录下 设置一个banner.(gif | png | jpg)文件
  2. yml文件中设置spring.banner.image.location值为文件路径 即可

兜底banner

当没有通过以上方式进行banner配置的时候,可以定义一个兜底的banner使其生效

  1. 在启动类中通过 springApplication.setBanner()来进行配置

关闭banner

  1. 在yml配置文件中 通过设置spring.main.banner-mode=off来关闭banner设置

banner获取原理

org.springframework.boot.SpringApplication#run(java.lang.String…)

/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		/*...*/
		try {
			/*...*/
			//1
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			/*...*/
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
    //1
	private Banner printBanner(ConfigurableEnvironment environment) {
	    //与 关闭banner 一栏相对应
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		if (printBannerViaDeprecatedMethod(environment)) {
			return null;
		}
		//获取一个ResourceLoader
		ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		//1.1 构建一个SpringApplicationBannerPrinter
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		//Mode : OFF(关闭)、CONSOLE(打印在控制台)、LOG(打印在日志中)
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		//1.2
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}
    //1.1
	SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
		this.resourceLoader = resourceLoader;
		//设置兜底的banner
		this.fallbackBanner = fallbackBanner;
	}
    //1.2
	public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
	    //1.2.1 获取banners集合
		Banner banner = getBanner(environment, this.fallbackBanner);
		//依次按照banners结合进行输出
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}
	//1.2.1 获取banners集合
	private static final Banner DEFAULT_BANNER = new SpringBootBanner();
	
	private Banner getBanner(Environment environment, Banner definedBanner) {
		Banners banners = new Banners();
		// 1.2.1.1 获取image banner
		banners.addIfNotNull(getImageBanner(environment));
		// 1.2.1.2 获取text banner
		banners.addIfNotNull(getTextBanner(environment));
		// 判断banners集合是否为空
		if (banners.hasAtLeastOneBanner()) {
		    //不为空则返回
			return banners;
		}
		//兜底banner是否为空
		if (this.fallbackBanner != null) {
		    //不为空返回兜底banner
			return this.fallbackBanner;
		}
		//返回 DEFAULT_BANNER
		return DEFAULT_BANNER;
	}

	private static class Banners implements Banner {
		private final List<Banner> banners = new ArrayList<Banner>();
	}
    // 1.2.1.1 
    static final String BANNER_IMAGE_LOCATION_PROPERTY = "banner.image.location";
    static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
    
	private Banner getImageBanner(Environment environment) {
	    //获取banner.image.location的属性值
		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);
		}
		//循环{ "gif", "jpg", "png" } 三个值
		for (String ext : IMAGE_EXTENSION) {
		    //拼接属性字段,分别为 “banner.gif”、“banner.jpg”、“banner.png”
			Resource resource = this.resourceLoader.getResource("banner." + ext);
		    //如果属性字段对应的值存在的话 并返回添加到调用的集合中
			if (resource.exists()) {
				return new ImageBanner(resource);
			}
		}
		return null;
	}
	// 1.2.1.2
	static final String BANNER_LOCATION_PROPERTY = "banner.location";
	static final String DEFAULT_BANNER_LOCATION = "banner.txt";
	
	private Banner getTextBanner(Environment environment) {
	    //判断是否存在"banner.location"的属性值,否则的话 获取"banner.txt"对应的值
		String location = environment.getProperty(BANNER_LOCATION_PROPERTY,
				DEFAULT_BANNER_LOCATION);
		Resource resource = this.resourceLoader.getResource(location);
		if (resource.exists()) {
		    //如果资源存在的话 并返回添加到调用的集合中
			return new ResourceBanner(resource);
		}
		//都不存在的话 返回null
		return null;
	}

流程总结

  • run方法体内调用 Banner printedBanner = printBanner(environment);
  • 调用获取banner逻辑
    - 获取banner中 调用getImageBanner方法
    - 可以通过spring.banner.image.location指定位置
    - 可使用图片格式
    - 获取banner中 调用getTextBanner方法
    - 可以通过spring.banner.location指定位置
    - 默认是banner.txt
    获取banner步骤

banner输出原理

入口

	public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
	    //获取的所有的banner
		Banner banner = getBanner(environment, this.fallbackBanner);
		//1 打印指定的banner
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}
		//1
		@Override
		public void printBanner(Environment environment, Class<?> sourceClass,
				PrintStream out) {
			//循环遍历所有的banners
			for (Banner banner : this.banners) {
			    //1.1 打印
			    //三中实现,一:SpringBootBanner,二:ResourceBanner
				banner.printBanner(environment, sourceClass, out);
			}
		}

默认输出源码

org.springframework.boot.SpringBootBanner#printBanner

	//1.1 SpringBootBanner
	private static final String[] BANNER = { "",
		"  .   ____          _            __ _ _",
		" /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\",
		"( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
		" \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )",
		"  '  |____| .__|_| |_|_| |_\\__, | / / / /",
		" =========|_|==============|___/=/_/_/_/" };
			
	@Override
	public void printBanner(Environment environment, Class<?> sourceClass,
			PrintStream printStream) {
		for (String line : BANNER) {
			//打印banner
			printStream.println(line);
		}
		//获取SpringBoot版本号
		String version = SpringBootVersion.getVersion();
		version = (version == null ? "" : " (v" + version + ")");
		String padding = "";
		while (padding.length() < STRAP_LINE_SIZE
				- (version.length() + SPRING_BOOT.length())) {
			padding += " ";
		}
		//输出带颜色的版本号,输出颜色字体为java自带功能,如:
		// System.out.println("\u001B[32m this is spring boot");
		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
				AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version));
		printStream.println();
	}

默认输出总结

  1. 先输出banner指定的内容
  2. 获取version信息
  3. 文本内容前后对齐
  4. 文本内容染色

文字banner输出源码

org.springframework.boot.ResourceBanner#printBanner

	//1.1 ResourceBanner
	@Override
	public void printBanner(Environment environment, Class<?> sourceClass,
			PrintStream out) {
		try {
		    //将指定的路径资源 转为String字符串
			String banner = StreamUtils.copyToString(this.resource.getInputStream(),
					environment.getProperty("banner.charset", Charset.class,
							Charset.forName("UTF-8")));
			//依次使用属性编辑器 去替换占位符,即:可以通过在文本中引用#{myTest},并在yml文件中定义 myTest: bannerTest, 来实现占位符属性值填充
			for (PropertyResolver resolver : getPropertyResolvers(environment,
					sourceClass)) {
				banner = resolver.resolvePlaceholders(banner);
			}
			//banner输出
			out.println(banner);
		}
		catch (Exception ex) {
			logger.warn("Banner not printable: " + this.resource + " (" + ex.getClass()
					+ ": '" + ex.getMessage() + "')", ex);
		}
	}

文字banner输出总结

  1. 可以通过spring.banner.charset指定字符集
  2. 获取文本内容
  3. 替换占位符
  4. 输出文本内容

图片banner输出源码

org.springframework.boot.ImageBanner#printBanner(org.springframework.core.env.Environment, java.lang.Class<?>, java.io.PrintStream)

	//1.1  ImageBanner
	@Override
	public void printBanner(Environment environment, Class<?> sourceClass,
			PrintStream out) {
		String headless = System.getProperty("java.awt.headless");
		try {
			//定义java是在没有显示器的模式下进行工作
			System.setProperty("java.awt.headless", "true");
			//1.1.1 进行打印
			printBanner(environment, out);
		}
		catch (Throwable ex) {
			log.warn("Image banner not printable: " + this.image + " (" + ex.getClass()
					+ ": '" + ex.getMessage() + "')");
			log.debug("Image banner printing failure", ex);
		}
		finally {
			if (headless == null) {
				System.clearProperty("java.awt.headless");
			}
			else {
				System.setProperty("java.awt.headless", headless);
			}
		}
	}
	//1.1.1 进行打印
	private void printBanner(Environment environment, PrintStream out)
			throws IOException {
		PropertyResolver properties = new RelaxedPropertyResolver(environment,
				"banner.image.");
		//获取宽、高、边距、是否旋转 等值,可通过banner.image.width、banner.image.height、banner.image.margin、banner.image.invert 来进行指定,否则使用默认值
		int width = properties.getProperty("width", Integer.class, 76);
		int height = properties.getProperty("height", Integer.class, 0);
		int margin = properties.getProperty("margin", Integer.class, 2);
		boolean invert = properties.getProperty("invert", Boolean.class, false);
		//调用绘图jar包记性
		BufferedImage image = readImage(width, height);
		//打印
		printBanner(image, margin, invert, out);
	}

图片banner输出总结

  1. 可以通过spring.banner.image.*设置图片属性
  2. 读取图片文件流
  3. 输出图片内容

面试题

  • 举例banner常见配置方式
  • 简述下框架内banner打印流程步骤
  • 说明下banner获取原理
  • 说明下banner输出原理
  • 说出你熟悉的banner属性有哪些
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值