繼續上一節
發現兩個參數的構造方法繼續調用了四個參數的構造參數
這個沒有什麼神奇的操作。簡單的賦值
我們繼續返回看那個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創建應用上下文