继续上一节
发现两个参数的构造方法继续调用了四个参数的构造参数
这个没有什么神奇的操作。简单的赋值
我们继续返回看那个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创建应用上下文