日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

以下內(nèi)容基于 Spring6.0.4。

這個(gè)話題其實(shí)非常龐大,我本來想從 getBean 方法講起,但一想這樣講完估計(jì)很多小伙伴就懵了,所以我們還是一步一步來,今天我主要是想和小伙伴們講講 Spring 容器創(chuàng)建 Bean 最最核心的 createBeanInstance 方法,這個(gè)方法專門用來創(chuàng)建一個(gè)原始 Bean 實(shí)例。

這里就以 Spring 源碼中方法的執(zhí)行順序?yàn)槔齺砗托』锇閭兎窒怼?/p>

1. doCreateBean

AbstractAutowireCapableBeanFactory#doCreateBean 就是 Bean 的創(chuàng)建方法,但是 Bean 的創(chuàng)建涉及到的步驟非常多,包括各種需要調(diào)用的前置后置處理器方法,今天我主要是想和大家聊聊單純的創(chuàng)建 Bean 的過程,其他方法咱們后面文章繼續(xù)。

在 doCreateBean 方法中,有如下一行方法調(diào)用:

protectedObject doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

throwsBeanCreationException {

// Instantiate the bean.

BeanWrApper instanceWrapper = null;

if(mbd.isSingleton) {

instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

}

if(instanceWrapper == null) {

instanceWrapper = createBeanInstance(beanName, mbd, args);

}

Object bean = instanceWrapper.getWrappedInstance;

//...

returnexposedObject;

}

createBeanInstance 這個(gè)方法就是真正的根據(jù)我們的配置去創(chuàng)建一個(gè) Bean 了。

2. createBeanInstance

先來看源碼:

protectedBeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){

// Make sure bean class is actually resolved at this point.

Class<?> beanClass = resolveBeanClass(mbd, beanName);

if(beanClass != null&& !Modifier.isPublic(beanClass.getModifiers) && !mbd.isNonPublicAccessAllowed) {

thrownewBeanCreationException(mbd.getResourceDeion, beanName,

"Bean class isn't public, and non-public access not allowed: "+ beanClass.getName);

}

Supplier<?> instanceSupplier = mbd.getInstanceSupplier;

if(instanceSupplier != null) {

returnobtAInFromSupplier(instanceSupplier, beanName);

}

if(mbd.getFactoryMethodName != null) {

returninstantiateUsingFactoryMethod(beanName, mbd, args);

}

// Shortcut when re-creating the same bean...

booleanresolved = false;

booleanautowireNecessary = false;

if(args == null) {

synchronized(mbd.constructorArgumentLock) {

if(mbd.resolvedConstructorOrFactoryMethod != null) {

resolved = true;

autowireNecessary = mbd.constructorArgumentsResolved;

}

}

}

if(resolved) {

if(autowireNecessary) {

returnautowireConstructor(beanName, mbd, null, null);

}

else{

returninstantiateBean(beanName, mbd);

}

}

// Candidate constructors for autowiring?

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

if(ctors != null|| mbd.getResolvedAutowireMode == AUTOWIRE_CONSTRUCTOR ||

mbd.hasConstructorArgumentValues || !ObjectUtils.isEmpty(args)) {

returnautowireConstructor(beanName, mbd, ctors, args);

}

// Preferred constructors for default construction?

ctors = mbd.getPreferredConstructors;

if(ctors != null) {

returnautowireConstructor(beanName, mbd, ctors, null);

}

// No special handling: simply use no-arg constructor.

returninstantiateBean(beanName, mbd);

}

這里就是核心的 Bean 的創(chuàng)建方法了,因此這個(gè)方法我來和大家詳細(xì)分析一下。

2.1 resolveBeanClass

這個(gè)方法是用來解析出來當(dāng)前的 beanClass 對(duì)象,它的 核心邏輯就是根據(jù)我們在 XML 文件中配置的類的全路徑,通過反射加載出來這個(gè) Class

@Nullable

protectedClass<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)

throwsCannotLoadBeanClassException {

if(mbd.hasBeanClass) {

returnmbd.getBeanClass;

}

returndoResolveBeanClass(mbd, typesToMatch);

}

首先會(huì)調(diào)用 mbd.hasBeanClass 方法去判斷是否已經(jīng)通過反射加載出來 beanClass 了,如果加載出來了就直接返回,沒有加載的話,就繼續(xù)執(zhí)行下面的 doResolveBeanClass 去加載。

什么時(shí)候會(huì)走 if 這條線呢?松哥舉一個(gè)例子,如果我們設(shè)置某一個(gè) Bean 的 Scope 是 prototype 的話,那么當(dāng)?shù)诙潍@取該 Bean 的實(shí)例的時(shí)候,就會(huì)走 if 這條線。

@Nullable

privateClass<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)

throwsClassNotFoundException {

//...

String className = mbd.getBeanClassName;

if(className != null) {

Object evaluated = evaluateBeanDefinitionString(className, mbd);

if(!className.equals(evaluated)) {

// A dynamically resolved expression, supported as of 4.2...

if(evaluated instanceofClass<?> clazz) {

returnclazz;

}

elseif(evaluated instanceofString str) {

className = str;

freshResolve = true;

}

else{

thrownewIllegalStateException( "Invalid class name expression result: "+ evaluated);

}

}

if(freshResolve) {

// When resolving against a temporary class loader, exit early in order

// to avoid storing the resolved Class in the bean definition.

if(dynamicLoader != null) {

returndynamicLoader.loadClass(className);

}

returnClassUtils.forName(className, dynamicLoader);

}

}

// Resolve regularly, caching the result in the BeanDefinition...

returnmbd.resolveBeanClass(beanClassLoader);

}

按理說,根據(jù)我們配置的類的全路徑加載出來一個(gè) Class 應(yīng)該是非常容易的,直接 Class.forName 就可以了。

但是!!!

如果對(duì) Spring 用法比較熟悉的小伙伴就知道,配置 Class 全路徑的時(shí)候,我們不僅可以像下面這樣老老實(shí)實(shí)配置:

< beanclass= "org.JAVAboy.bean.Book"/>

我們甚至可以使用 SpEL 來配置 Bean 名稱,例如我有如下類:

publicclassBeanNameUtils{

publicString getName{

return"org.javaboy.bean.User";

}

}

這里有一個(gè) getName 方法,這個(gè)方法返回的是一個(gè)類的全路徑,現(xiàn)在我們在 XML 文件中可以這樣配置:

< beanclass= "org.javaboy.bean.BeanNameUtils"id= "beanNameUtils"/>

< beanclass= "#{beanNameUtils.name}"id= "user"/>

在 XML 的 class 屬性中,我們可以直接使用 SpEL 去引用一個(gè)方法的執(zhí)行,用該方法的返回值作為 class 的值。

了解了 Spring 中的這個(gè)玩法,再去看上面的源碼就很好懂了:

  • 首先調(diào)用 mbd.getBeanClassName; 去獲取到類路徑。

  • 接下來調(diào)用 evaluateBeanDefinitionString 方法進(jìn)行 SpEL 運(yùn)算,這個(gè)運(yùn)算的目的是為了解析 className 中的 SpEL 表達(dá)式,當(dāng)然,一般情況下 className 就是一個(gè)普通的字符串,不是 SpEL 表達(dá)式,那么解析完成之后就還是原本的字符串。如果是 className 是一個(gè) SpEL,那么合法的解析結(jié)果分為兩種:

    • 首先就是解析之后拿到了一個(gè) Class,那這個(gè)就是我們想要的結(jié)果,直接返回即可。

    • 要么就是解析出來是一個(gè)字符串,松哥上面舉的例子就是這種情況,那么就把這個(gè)字符串賦值給 className,并且將 freshResolve 屬性設(shè)置為 true,然后在接下來的 if 分支中去加載 Class。

當(dāng)然,上面這些都是處理特殊情況,一般我們配置的普通 Bean,都是直接走最后一句 mbd.resolveBeanClass(beanClassLoader) ,這個(gè)方法的邏輯其實(shí)很好懂,我把代碼貼出來小伙伴們來瞅一瞅:

@Nullable

publicClass<?> resolveBeanClass( @NullableClassLoader classLoader) throwsClassNotFoundException {

String className = getBeanClassName;

if(className == null) {

returnnull;

}

Class<?> resolvedClass = ClassUtils.forName(className, classLoader);

this.beanClass = resolvedClass;

returnresolvedClass;

}

這個(gè)方法就相當(dāng)直白了,根據(jù) className 加載出來 Class 對(duì)象,然后給 beanClass 屬性也設(shè)置上值,這就和一開始的 if (mbd.hasBeanClass) 對(duì)應(yīng)上了。

好了,到此,我們總算是根據(jù) className 拿到 Class 對(duì)象了。

2.2 Supplier 和 factory-method

好了,回到一開始的源碼中,接下來該執(zhí)行如下兩行代碼了:

Supplier<?> instanceSupplier = mbd.getInstanceSupplier;

if(instanceSupplier != null) {

returnobtainFromSupplier(instanceSupplier, beanName);

}

if(mbd.getFactoryMethodName != null) {

returninstantiateUsingFactoryMethod(beanName, mbd, args);

}

這兩個(gè)松哥在前面的文章中和小伙伴們已經(jīng)講過了(Spring5 中更優(yōu)雅的第三方 Bean 注入):前面的 obtainFromSupplier 方法是 Spring5 開始推出來的 Supplier,通過回調(diào)的方式去獲取一個(gè)對(duì)象;第二個(gè)方法 instantiateUsingFactoryMethod 則是通過配置的 factory-method 來獲取到一個(gè) Bean 實(shí)例。

對(duì)這兩個(gè)方法不熟悉的小伙伴可以參考前面的文章:Spring5 中更優(yōu)雅的第三方 Bean 注入。

2.3 re-create 邏輯

繼續(xù)回到一開始的源碼中,接下來是一段 re-create 的處理邏輯,如下:

booleanresolved = false;

booleanautowireNecessary = false;

if(args == null) {

synchronized(mbd.constructorArgumentLock) {

if(mbd.resolvedConstructorOrFactoryMethod != null) {

resolved = true;

autowireNecessary = mbd.constructorArgumentsResolved;

}

}

}

if(resolved) {

if(autowireNecessary) {

returnautowireConstructor(beanName, mbd, null, null);

}

else{

returninstantiateBean(beanName, mbd);

}

}

根據(jù)前面的介紹,我們現(xiàn)在已經(jīng)獲取到 Class 對(duì)象了,接下來直接調(diào)用相應(yīng)的構(gòu)造方法就可以獲取到 Bean 實(shí)例了。但是這個(gè) Class 對(duì)象可能存在多個(gè)構(gòu)造方法,所以還需要一堆流程去確定到底調(diào)用哪個(gè)構(gòu)造方法。

所以這里會(huì)先去判斷 resolvedConstructorOrFactoryMethod 是否不為空,不為空的話,說明這個(gè) Bean 之前已經(jīng)創(chuàng)建過了,該用什么方法創(chuàng)建等等問題都已經(jīng)確定了,所以這次就不用重新再去確定了( resolved = true )。另一方面,autowireNecessary 表示構(gòu)造方法的參數(shù)是否已經(jīng)處理好了,這個(gè)屬性為 true 則表示構(gòu)造方法的參數(shù)已經(jīng)處理好了,那么就可以調(diào)用 autowireConstructor 方法去創(chuàng)建一個(gè) Bean 出來,否則調(diào)用 instantiateBean 方法初始化 Bean。

這里涉及到的 autowireConstructor 和 instantiateBean 方法我們先不細(xì)說了,因?yàn)樵诤竺孢€會(huì)再次涉及到。

2.4 構(gòu)造器注入

繼續(xù)回到一開始的源碼中,接下來就是針對(duì)各種處理器的預(yù)處理了:

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

if(ctors != null|| mbd.getResolvedAutowireMode == AUTOWIRE_CONSTRUCTOR ||

mbd.hasConstructorArgumentValues || !ObjectUtils.isEmpty(args)) {

returnautowireConstructor(beanName, mbd, ctors, args);

}

先來看 determineConstructorsFromBeanPostProcessors 方法,這個(gè)方法主要是考慮到你可能提供了 SmartInstantiationAwareBeanPostProcessor,松哥在前面的文章中和大家專門講過 BeanPostProcessor( BeanFactoryPostProcessor 和 BeanPostProcessor 有什么區(qū)別? ),這里的 SmartInstantiationAwareBeanPostProcessor 算是 BeanPostProcessor 的一種,也是 Bean 的一種增強(qiáng)器。SmartInstantiationAwareBeanPostProcessor 中有一個(gè) determineCandidateConstructors 方法,這個(gè)方法返回某一個(gè) Bean 的構(gòu)造方法,將來可以通過這個(gè)構(gòu)造方法初始化某一個(gè) Bean。

我給大家舉一個(gè)簡單例子,假設(shè)我有如下類:

publicclassUser{

privateString username;

privateString address;

publicUser{

System.out.println( "=====no args=====");

}

publicUser(ObjectProvider<String> username){

System.out.println( "args==username");

this.username = username.getIfAvailable;

}

//省略 getter/setter/toString

}

現(xiàn)在我在 Spring 容器中注冊這個(gè)對(duì)象:

< beanclass= "org.javaboy.bean.User"id= "user">

</ bean>

按照我們已有的知識(shí),這個(gè)將來會(huì)調(diào)用 User 的無參構(gòu)造方法去完成 User 對(duì)象的初始化。

但是現(xiàn)在,假設(shè)我添加如下一個(gè)處理器:

publicclassMySmartInstantiationAwareBeanPostProcessorimplementsSmartInstantiationAwareBeanPostProcessor{

@Override

publicConstructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throwsBeansException {

if( "user".equals(beanName)) {

Constructor<?> constructor = null;

try{

constructor = beanClass.getConstructor(ObjectProvider . class) ;

} catch(NoSuchMethodException e) {

thrownewRuntimeException(e);

}

returnnewConstructor[]{constructor};

}

returnSmartInstantiationAwareBeanPostProcessor. super.determineCandidateConstructors(beanClass, beanName);

}

}

在 determineCandidateConstructors 方法中,返回一個(gè)有參構(gòu)造方法,那么將來 Spring 容器會(huì)通過這里返回的有參構(gòu)造方法去創(chuàng)建 User 對(duì)象,而不是通過無參構(gòu)造方法去創(chuàng)建 User 對(duì)象。

最后,將這個(gè)處理器注冊到 Spring 容器:

< beanclass= "org.javaboy.bean.MySmartInstantiationAwareBeanPostProcessor"/>

現(xiàn)在,當(dāng)我們啟動(dòng) Spring 容器的時(shí)候,User 就是通過有參構(gòu)造方法初始化的,而不是無參構(gòu)造方法。之所以會(huì)這樣,就是因?yàn)楸拘」?jié)一開始提到的源碼 determineConstructorsFromBeanPostProcessors ,這個(gè)方法就是去查看有無 SmartInstantiationAwareBeanPostProcessor,如果有,就調(diào)用對(duì)應(yīng)的方法找到處理器并返回。

這個(gè)弄懂之后,if 中其他幾種情況就好理解了, mbd.getResolvedAutowireMode 是查看當(dāng)前對(duì)象的注入方式,這個(gè)一般是在 XML 中配置的,不過日常開發(fā)中我們一般不會(huì)配置這個(gè)屬性,如果需要配置,方式如下:

< beanclass= "org.javaboy.bean.User"id= "user"autowire= "constructor">

</ bean>

如果添加了 autowire="constructor" 就表示要通過構(gòu)造方法進(jìn)行注入,那么這里也會(huì)進(jìn)入到 if 中。

if 里邊剩下的幾個(gè)條件都好說,就是看是否有配置構(gòu)造方法參數(shù),如果配置了,那么也直接調(diào)用相應(yīng)的構(gòu)造方法就行了。

這里最終執(zhí)行的是 autowireConstructor 方法,這個(gè)方法比較長,我就不貼出來了,和大家說一說它的思路:

  1. 首先把能獲取到的構(gòu)造方法都拿出來,如果構(gòu)造方法只有一個(gè),且目前也沒有任何和構(gòu)造方法有關(guān)的參數(shù),那就直接用這個(gè)構(gòu)造方法就行了。

  2. 如果第一步不能解決問題,接下來就遍歷所有的構(gòu)造方法,并且和已有的參數(shù)進(jìn)行參數(shù)數(shù)量和類型比對(duì),找到合適的構(gòu)造方法并調(diào)用。

2.5 PreferredConstructors

繼續(xù)回到一開始的源碼中,接下來是這樣了:

ctors = mbd.getPreferredConstructors;

if(ctors != null) {

returnautowireConstructor(beanName, mbd, ctors, null);

}

這塊代碼看字面好理解,就是獲取到主構(gòu)造方法,不過這個(gè)是針對(duì) Kotlin 的,跟我們 Java 無關(guān),我就不啰嗦了。

2.6 instantiateBean

最后就是 instantiateBean 方法了,這個(gè)方法就比較簡單了,我把代碼貼一下小伙伴們應(yīng)該自己都能看明白:

protectedBeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd){

try{

Object beanInstance = getInstantiationStrategy.instantiate(mbd, beanName, this);

BeanWrapper bw = newBeanWrapperImpl(beanInstance);

initBeanWrapper(bw);

returnbw;

}

catch(Throwable ex) {

thrownewBeanCreationException(mbd.getResourceDeion, beanName, ex.getMessage, ex);

}

}

@Override

publicObject instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner){

// Don't override the class with CGLIB if no overrides.

if(!bd.hasMethodOverrides) {

Constructor<?> constructorToUse;

synchronized(bd.constructorArgumentLock) {

constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;

if(constructorToUse == null) {

finalClass<?> clazz = bd.getBeanClass;

if(clazz.isInterface) {

thrownewBeanInstantiationException(clazz, "Specified class is an interface");

}

try{

constructorToUse = clazz.getDeclaredConstructor;

bd.resolvedConstructorOrFactoryMethod = constructorToUse;

}

catch(Throwable ex) {

thrownewBeanInstantiationException(clazz, "No default constructor found", ex);

}

}

}

returnBeanUtils.instantiateClass(constructorToUse);

}

else{

// Must generate CGLIB subclass.

returninstantiateWithMethodInjection(bd, beanName, owner);

}

}

從上面小伙伴么可以看到,本質(zhì)上其實(shí)就是調(diào)用了 constructorToUse = clazz.getDeclaredConstructor; ,獲取到一個(gè)公開的無參構(gòu)造方法,然后據(jù)此創(chuàng)建一個(gè) Bean 實(shí)例出來。

3. 小結(jié)

好了,這就是 Spring 容器中 Bean 的創(chuàng)建過程,我這里單純和小伙伴們分享了原始 Bean 的創(chuàng)建這一個(gè)步驟,這塊內(nèi)容其實(shí)非常龐雜,以后有空我會(huì)再和小伙伴們分享。

最后,給上面分析的方法生成了一個(gè)時(shí)序圖,小伙伴們作為參考。

其實(shí)看 Spring 源碼,松哥最大的感悟就是小伙伴們一定要了解 Spring 的各種用法,在此基礎(chǔ)之上,源碼就很好懂,如果你只會(huì) Spring 一些基本用法,那么源碼一定是看得云里霧里的。

END

分享到:
標(biāo)簽:容器 Spring
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評(píng)定2018-06-03

通用課目體育訓(xùn)練成績評(píng)定