spring-boot啟動過程中的實例化方式

前言
最近一直在肝spring boot的源碼,這么久了真的感覺挺上頭的,不過昨天總算是結(jié)束了這個漫長的過程,所以從今天開始我們的內(nèi)容會稍微輕松一點,然后內(nèi)容上也會更豐富一些。
但是由于之前的分享過程中還有一些遺漏和缺失,因此近期還是會在之前的基礎(chǔ)上做一些補(bǔ)充,當(dāng)然也會有一些總結(jié)的內(nèi)容,今天我們來看下spring boot啟動過程中的集中實例化方式,也算是對spring boot實例化這塊的一個簡單梳理和總結(jié)。
實例化方式
根據(jù)最近一段時間對spring boot啟動過程的研究和摸索,我發(fā)現(xiàn)spring boot常用的實例化方式主要有四種,一種是通過newInstance的方式,第二種是new的方式,這種主要是初始化某些組件的屬性,第三種是supplier,這種方式就比較高級了,我也是最近才發(fā)現(xiàn)這種方式,最后一種就是工廠方法,這種方式是最古老的實例化方法,當(dāng)然也在spring boot的初始化過程頻繁出現(xiàn)。
下面我們就分別展開分享下這幾種實例化方式。
newInstance
這種方式好多小伙伴都知道,也特別常用,很多小伙伴第一次接觸就是在java調(diào)用mySql驅(qū)動的時候,首先是通過Class.forName拿到類的class,然后通過class的newInstance方法構(gòu)建類的實例:
try {
Class<?> contextClass = Class.forName("java.lang.String");
String str = (String)contextClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
這里最典型的就是spring boot在創(chuàng)建容器實例的時候,當(dāng)然spring boot的實例化要比我這里寫的高級,它是調(diào)用class的構(gòu)造方法進(jìn)行實例化的,是可以指定參數(shù)的,我這里演示的調(diào)用的是無參構(gòu)造方法:



new
這種方式在spring boot初始化過程中也經(jīng)常出現(xiàn),通常是在初始化相關(guān)組件的屬性的時候。


這種方式就不需要過多解釋了,我們通常情況下都是通過new的方式實例化對象的。
supplier
這種方式相比前面兩種,要高級一點,首先是它比較新,是jdk 1.8引入的新功能,在使用方面也很簡單:
和前面兩種初始化比起來,它更靈活,下面我們看下關(guān)于它的示例:
Supplier<String> stringSupplier = String::new;
String s = stringSupplier.get();
從形式上看,它其實是基于lambda實現(xiàn)的,也就是我們常說的函數(shù)式編程,看起來也很簡潔。
其中第一行定義了初始化要調(diào)用的方法,這時并沒有進(jìn)行實例化,當(dāng)你執(zhí)行第二行的get操作時,這時候開始實例化。
這種方式在spring boot的初始化過程中出現(xiàn)頻率也很高,但是由于其本身比較隱晦,所以很難發(fā)現(xiàn)。
下面就是spring boot中使用supplier這種方式的幾個方法,可以看到全部都是在注冊bean的時候調(diào)用的:


這些方法都是在spring 5.0以后引入的,這可能也是我沒有找到spring boot集中實例化對象然后再注入容器的相關(guān)代碼的原因。
bean的supplier通常被綁定在其BeanDefainition信息下的instanceSupplier屬性下:

比如下面這個注冊BeanDefinitionRegistry的方法就是通過這種方式將supplier注入beanDefinition中的
private void register(BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean::new).getBeanDefinition();
registry.registerBeanDefinition("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory", definition);
}
這樣在注冊bean的時候,只需要執(zhí)行的BeanDefainition下instanceSupplier方法即可獲取該對象的實例,確實要比前兩種更靈活。
工廠方法
這種方式雖然存在,但是不太好找,所以這里就不展示了,但是在beanDefinition信息中我們看到了factoryMethodName,這個就是bean的工廠方法名稱:
總結(jié)
好了,關(guān)于spring boot的四種初始化方式我們就先說這么多,這里需要特別關(guān)注的是第三種方式,算是一個比較新的知識點。
另外,關(guān)于工廠方法確實在spring boot現(xiàn)在的源碼中不好找,后面看情況,如果有幸被我遇到了,我們到時候再來分享。
好了,各位小伙伴晚安吧!
- END -