springboot 源码解析(4)打印的banner原理以及如何修改

本文深入解析了SpringBoot启动时打印Banner的原理,从构造方法到bind过程,详细探讨了Banner的加载逻辑。通过分析源码,了解到可以自定义Banner的方式,包括放置图片或文本文件到resource目录下,以替换默认的启动Logo。
摘要由CSDN通过智能技术生成

继续上一节

发现两个参数的构造方法继续调用了四个参数的构造参数

这个没有什么神奇的操作。简单的赋值

我们继续返回看那个bind方法

我们先看看

Bindable.ofInstance(this)干啥了

instance是SpringApplication本身 type取到类,这里有个of(type)我们瞧瞧他又是干啥的

先看ResolvableType.forClass(type)闹啥了

new了一个ResolvableType对象。感觉没有那么简单。我们进去看看他怎么构建这个对象的

如果这个类是空的。给resolved赋值Object.class其他的都很简单。我们继续返回看

of(ResolvableType.forClass(type));

 

我们看看box又在玩什么花样

Class<?> resolved = type.resolve();获取到类
if (resolved != null && resolved.isPrimitive())   如果不为空并且他是原始类型
isPrimitive 类的内部方法,是否是原始类型
Object array = Array.newInstance(resolved, 1);创建一个数组
Class<?> wrapperType = Array.get(array, 0).getClass();获取数组的第一个类
return ResolvableType.forClass(wrapperType);返回包装了原始类型的ResolvableType对象
if (resolved != null && resolved.isArray())  如果不为空并且是个数组返回一个数组的ResolvableType对象 否则直接返回
return type;

我们继续返回看

new Bindable<>(type, boxedType, null, NO_ANNOTATIONS);创建了一个没有注解的bindable对象

然后返回继续看

我们跟进去看

调用了以后还是返回了一个Bindable对象

我们继续看

我们跟进去看bind

我们先看ConfigurationPropertyName.of(name)  此时name是“spring.main”

我们继续看这个of方法做了什么

static ConfigurationPropertyName of(CharSequence name, boolean returnNullIfInvalid) {
   if (name == null) {
      Assert.isTrue(returnNullIfInvalid, "Name must not be null");
      return null;
   }
   if (name.length() == 0) {
      return EMPTY;
   }
   if (name.charAt(0) == '.' || name.charAt(name.length() - 1) == '.') {
      if (returnNullIfInvalid) {
         return null;
      }
      throw new InvalidConfigurationPropertyNameException(name,
            Collections.singletonList('.'));
   }
   Elements elements = new ElementsParser(name, '.').parse();
   for (int i = 0; i < elements.getSize(); i++) {
      if (elements.getType(i) == ElementType.NON_UNIFORM) {
         if (returnNullIfInvalid) {
            return null;
         }
         throw new InvalidConfigurationPropertyNameException(name,
               getInvalidChars(elements, i));
      }
   }
   return new ConfigurationPropertyName(elements);
}

上面的校验不多解释。都能看懂。方法返回了一个配置文件的对象

我们返回去看bind方法

BindHandler.DEFAULT

这里用到一个java8的新特性接口DEFAULT  接口中可以有方法的实现,必须用DEFAULT和static修饰,此方法可以被重写

Context context = new Context();终于看到一个大家非常熟悉的东西了。new了一个context,这里就用了一个new,但是之前的分析感觉他并不只是new一个对象。我们跟进去看

真是玄机无处不在。不过这个我们之前分析过了。这里就不在分析了。他只是给赋值而已

我们继续往下看

T bound = bind(name, target, handler, context, false);

我们看看这个bind有搞什么名堂,我点!点进去看

刚进来就clear,刚进家就打扫下家?这肯定是消灭家里藏人的证据!

context.clearConfigurationProperty();

我们继续往下瞅,嗯?handler刚才不是个接口吗。怎么直接调用方法了。刚才咱们说过了

default修饰的方法是可以再接口中实现的。这个好像叫什么默认实现?

 

我们继续往下看

Object bound = bindObject(name, target, handler, context,
      allowRecursiveBinding);

大家有点耐心我们继续往下看

ConfigurationProperty property = findProperty(name, context);这个不多解释了。从content中获取配置信息

这里返回了null并没有找到,这不是关键的。我们继续往下看

 handleBindResult(name, target, handler, context, bound);

这个里面逻辑也是比较简单。我们先不做赘述了。他返回的依然是null

主要的是我们看这个。他返回了一个BindResult

我们再回到

org.springframework.boot.SpringApplication#prepareEnvironment

if (!this.isCustomEnvironment) {
   environment = new EnvironmentConverter(getClassLoader())
         .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}

创建了一个标准的环境StandardEnvironment

然后我们再返回到

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

看到

configureIgnoreBeanInfo(environment);

这个的大概意思是获取配置

spring.beaninfo.ignore  生成bean的模式默认是单例模式,读取配置文件读取不到就设置为单例模式。然后设置到系统配置中
Banner printedBanner = printBanner(environment);

顾名思义打印banner,我们看看他有哪些实现

this.bannerMode == Banner.Mode.OFF是否关闭打印banner
ResourceLoader resourceLoader = (this.resourceLoader != null)
      ? this.resourceLoader : new DefaultResourceLoader(getClassLoader());  获取默认资源加载器
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
      resourceLoader, this.banner);

构建一个spring的banner

if (this.bannerMode == Mode.LOG) {
   return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}

判断是否打印到log的

我们进入print看

我们看getBanner

Banners banners = new Banners();创建一个banners的对象
banners.addIfNotNull(getImageBanner(environment));我们跟进去看获取图片banner

static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";我们发现她是查找配置文件是否配置了这个属性
if (StringUtils.hasLength(location)) {
   Resource resource = this.resourceLoader.getResource(location);
   return resource.exists() ? new ImageBanner(resource) : null;
}

如果存在配置 并且文件存在获取这个图片的banner返回

如果没有配置往下继续

for (String ext : IMAGE_EXTENSION) {
   Resource resource = this.resourceLoader.getResource("banner." + ext);
   if (resource.exists()) {
      return new ImageBanner(resource);
   }
}
static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };他开始寻找能否找到resource下面banner+后缀的的图片

如果存在就返回。也就是说如果我们想替换banner可以直接在resource下面放一个banner.png|jpg|gif的文件就可以了

我们再看文本格式的banner

banners.addIfNotNull(getTextBanner(environment));

static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
static final String DEFAULT_BANNER_LOCATION = "banner.txt";

这个原理一样首先查找配置,如果配置不存就查找banner.txt

if (banners.hasAtLeastOneBanner()) {
   return banners;
}

如果包含至少一个banner返回

如果不存在

private static final Banner DEFAULT_BANNER = new SpringBootBanner();

这个熟悉了吧

banner.printBanner(environment, sourceClass, out);打印banner

如果存在两个两个都会打印。不信你看

好了先到这里。打印banner已经分析完毕。下一步我们开始

createApplicationContext创建应用上下文

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值