SpringBoot打印banner

本文深入解析SpringBoot启动过程中的Banner打印机制,包括文本和图片Banner的配置与打印流程,揭示了SpringBoot如何读取并展示自定义Banner。

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


本文通过解读springboot启动源码中,看看banner是怎么执行打印,并了解一下可以怎么配置打印

1. 可以打印什么样的banner

不说了,先上代码:
代码截取了SpringApplication.class中run方法:

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			Banner printedBanner = printBanner(environment);
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			/////////////////////看这里,就是这里执行了打印banner的 ////////////////////////////////
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(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, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

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

1.1. 源码分析可得知:

  • 源码中可以看出,打印banner是在springApplication初始化完成以后再执行的(在run方法内执行)。
  • 执行打印之前,先加载配置环境ConfigurableEnvironment environment ,实体类是StandardServletEnvironment。
  • 打印banner之前,开启了SpringApplicationRunListeners的监听,开始了监听spring的整个生命周期。
  • 加载和打印banner,是计算再启动时间内的。

2. 看看printBanner(environment)方法内部

	private Banner printBanner(ConfigurableEnvironment environment) {
		// private Banner.Mode bannerMode = Banner.Mode.CONSOLE; 默认值是这个
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		// ResourceLoader这是一个加载资源的接口,下面要加载banner的内容需要的
		// private ResourceLoader resourceLoader; 默认值是null
		// 所以来ResourceLoader 的实体类是 DefaultResourceLoader
		ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader()));
				
		// 实例化一个打印banner的对象
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
				
		// private Banner.Mode bannerMode = Banner.Mode.CONSOLE; 这是默认值
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		// 默认情况下执行这里的banner打印
		// 在这里,内部执行了读取banner内容和打印banner,所以详细读这个方法内部的源码
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

3. SpringApplicationBannerPrinter 源码解读

class SpringApplicationBannerPrinter {
	// 打印bananer调用了这个方法
	public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
		// 获取banner对象,返回的Banner对象可能有两种情况
		// 1.如果我们配置了banner,就会返回Banners的实体
		// 2.如果我们没有配置,就会是spring默认的SpringBootBanner对象
		// banner的加入顺序是先添加图片banner在添加文本banner
		Banner banner = getBanner(environment);
		// 具体的打印代码如果感兴趣,可以去读一读。
		// 这里只是简单的提一下,打印的顺序与添加的顺序一致
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}
	
	// 获取banner对象的方法
	private Banner getBanner(Environment environment) {
		// 这是一个多个banner组成的banner对象
		Banners banners = new Banners();
		// 添加图片banner
		banners.addIfNotNull(getImageBanner(environment));
		// 添加文本banner
		banners.addIfNotNull(getTextBanner(environment));
		// 如果banners不是空的(即,如果我们配置了banner),则返回banners
		if (banners.hasAtLeastOneBanner()) {
			return banners;
		}
		// private final Banner fallbackBanner; 默认是null
		// 所以默认不会是这个banner
		if (this.fallbackBanner != null) {
			return this.fallbackBanner;
		}
		// 这是默认的banner,当我们没有做任何banner配置的时候,就会使用这个默认的springboot的banner对象
		/*
		  .   ____          _            __ _ _
		 /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\
		( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\
		 \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
		  '  |____| .__|_| |_|_| |_\\__, | / / / /
		 =========|_|==============|___/=/_/_/_/
		*/
		// 这个springboot的banner对象已经很熟悉了,一个大大的springboot,这里就不详细解说了
		// private static final Banner DEFAULT_BANNER = new SpringBootBanner();
		return DEFAULT_BANNER;
	}
	
	// 获取文本banner的方法
	private Banner getTextBanner(Environment environment) {
		/*
			此方法代码并不复杂,可以看出,spring是读取文本banner是两个地方 
			1.配置文件中spring.banner.location配置的banner
			2.如果么有配置spring.banner.location,那么就默认是classPath下的banner.txt文件
		*/
		// static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
		// static final String DEFAULT_BANNER_LOCATION = "banner.txt";
		String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);
		// 3.读取资源文件
		Resource resource = this.resourceLoader.getResource(location);
		if (resource.exists()) {
			return new ResourceBanner(resource);
		}
		// 如果读取不到,则认为,我们没有配置文本banner
		return null;
	}
	
	// 获取图片banner的办法
	private Banner getImageBanner(Environment environment) {
		// 1.读取配置中的图片banner配置
		// static final 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);
			return (resource.exists() ? new ImageBanner(resource) : null);
		}
		// 2.读取classPath下的banner.gif、banner.jpg、banner.png
		// static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
		for (String ext : IMAGE_EXTENSION) {
			Resource resource = this.resourceLoader.getResource("banner." + ext);
			if (resource.exists()) {
				return new ImageBanner(resource);
			}
		}
		// 3.如果都都不到,则认为我们没有配置图片banner
		return null;
	}
}

4. 总结

通过阅读源码可以得知:

  • 配置banner可以有两种,图片banner和文本banner
  • 文本banner只能配置一个,图片banner也只能配置一个,如果一个banner都不配置,就会使用默认的springboot的banner。
  • 文本banner和图片banner可以同时配置,两个都会打印,先打印图片banner。
  • 配置文本banner有两种方式:
    • 配置文本banner的路径,配置的key是spring.banner.location。
    • 可以不配置spring.banner.location的值,直接在classPath中放入一个banner.txt文件。
    • 如果配置了spring.banner.location的值,就不会读取banner.txt文件作为文本banner。
  • 配置图片banner也是两种方式:
    • 配置图片banner的路径,key是spring.banner.image.location。
    • 也可以不配置路径,可以在classPath中添加banner.gif、banner.jpg、banner.png其中一个文件,如果添加多个,只会打印一个,有限级:“gif” > “jpg” > “png”。
    • 如果配置了spring.banner.image.location的值,就不会读取banner.gif、banner.jpg、banner.png任何一个作为图片banner。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值