摘要:你也會(huì)了解到構(gòu)造對(duì)象的兩種策略。構(gòu)造方法參數(shù)數(shù)量低于配置的參數(shù)數(shù)量,則忽略當(dāng)前構(gòu)造方法,并重試。通過默認(rèn)構(gòu)造方法創(chuàng)建對(duì)象看完了上面冗長(zhǎng)的邏輯,本節(jié)來看點(diǎn)輕松的吧通過默認(rèn)構(gòu)造方法創(chuàng)建對(duì)象。
1. 簡(jiǎn)介
本篇文章是上一篇文章(創(chuàng)建單例 bean 的過程)的延續(xù)。在上一篇文章中,我們從戰(zhàn)略層面上領(lǐng)略了doCreateBean方法的全過程。本篇文章,我們就從戰(zhàn)術(shù)的層面上,詳細(xì)分析doCreateBean方法中的一個(gè)重要的調(diào)用,即createBeanInstance方法。在本篇文章中,你將看到三種不同的構(gòu)造 bean 對(duì)象的方式。你也會(huì)了解到構(gòu)造 bean 對(duì)象的兩種策略。如果你對(duì)這些內(nèi)容感興趣,那么不妨繼續(xù)往下讀。我會(huì)在代碼進(jìn)行大量的注解,相信能幫助你理解代碼邏輯。好了,其他的就不多說了,進(jìn)入正題吧。
2. 源碼分析 2.1 創(chuàng)建 bean 對(duì)象的過程本節(jié),我們一起來來分析一下本篇文章的主角createBeanInstance方法。按照慣例,我們還是先分析一下方法的大致脈絡(luò),然后我們?cè)侔凑者@個(gè)脈絡(luò)去分析一些重要的調(diào)用。So. Let`s go → ↓
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { Class> beanClass = resolveBeanClass(mbd, beanName); /* * 檢測(cè)類的訪問權(quán)限。默認(rèn)情況下,對(duì)于非 public 的類,是允許訪問的。 * 若禁止訪問,這里會(huì)拋出異常 */ if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn"t public, and non-public access not allowed: " + beanClass.getName()); } /* * 如果工廠方法不為空,則通過工廠方法構(gòu)建 bean 對(duì)象。這種構(gòu)建 bean 的方式 * 就不深入分析了,有興趣的朋友可以自己去看一下。 */ if (mbd.getFactoryMethodName() != null) { // 通過“工廠方法”的方式構(gòu)建 bean 對(duì)象 return instantiateUsingFactoryMethod(beanName, mbd, args); } /* * 當(dāng)多次構(gòu)建同一個(gè) bean 時(shí),可以使用此處的快捷路徑,即無需再次推斷應(yīng)該使用哪種方式構(gòu)造實(shí)例, * 以提高效率。比如在多次構(gòu)建同一個(gè) prototype 類型的 bean 時(shí),就可以走此處的捷徑。 * 這里的 resolved 和 mbd.constructorArgumentsResolved 將會(huì)在 bean 第一次實(shí)例 * 化的過程中被設(shè)置,在后面的源碼中會(huì)分析到,先繼續(xù)往下看。 */ boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { // 通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象 return autowireConstructor(beanName, mbd, null, null); } else { // 通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象 return instantiateBean(beanName, mbd); } } // 由后置處理器決定返回哪些構(gòu)造方法,這里不深入分析了 Constructor>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); /* * 下面的條件分支條件用于判斷使用什么方式構(gòu)造 bean 實(shí)例,有兩種方式可選 - 構(gòu)造方法自動(dòng) * 注入和默認(rèn)構(gòu)造方法。判斷的條件由4部分綜合而成,如下: * * 條件1:ctors != null -> 后置處理器返回構(gòu)造方法數(shù)組是否為空 * * 條件2:mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR * -> bean 配置中的 autowire 屬性是否為 constructor * 條件3:mbd.hasConstructorArgumentValues() * -> constructorArgumentValues 是否存在元素,即 bean 配置文件中 * 是否配置了* 條件4:!ObjectUtils.isEmpty(args) * -> args 數(shù)組是否存在元素,args 是由用戶調(diào)用 * getBean(String name, Object... args) 傳入的 * * 上面4個(gè)條件,只要有一個(gè)為 true,就會(huì)通過構(gòu)造方法自動(dòng)注入的方式構(gòu)造 bean 實(shí)例 */ if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { // 通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象 return autowireConstructor(beanName, mbd, ctors, args); } // 通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象 return instantiateBean(beanName, mbd); }
以上就是 createBeanInstance 方法的源碼,不是很長(zhǎng)。配合著注釋,應(yīng)該不是很難懂。下面我們來總結(jié)一下這個(gè)方法的執(zhí)行流程,如下:
檢測(cè)類的訪問權(quán)限,若禁止訪問,則拋出異常
若工廠方法不為空,則通過工廠方法構(gòu)建 bean 對(duì)象,并返回結(jié)果
若構(gòu)造方式已解析過,則走快捷路徑構(gòu)建 bean 對(duì)象,并返回結(jié)果
如第三步不滿足,則通過組合條件決定使用哪種方式構(gòu)建 bean 對(duì)象
這里有三種構(gòu)造 bean 對(duì)象的方式,如下:
通過“工廠方法”的方式構(gòu)造 bean 對(duì)象
通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象
通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象
下面我將會(huì)分析第2和第3種構(gòu)造 bean 對(duì)象方式的實(shí)現(xiàn)源碼。至于第1種方式,實(shí)現(xiàn)邏輯和第2種方式較為相似。所以就不分析了,大家有興趣可以自己看一下。
2.2 通過構(gòu)造方法自動(dòng)注入的方式創(chuàng)建 bean 實(shí)例本節(jié),我將會(huì)分析構(gòu)造方法自動(dòng)注入的實(shí)現(xiàn)邏輯。代碼邏輯較為復(fù)雜,需要大家耐心閱讀。代碼如下:
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, Constructor>[] ctors, Object[] explicitArgs) { // 創(chuàng)建 ConstructorResolver 對(duì)象,并調(diào)用其 autowireConstructor 方法 return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); } public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd, Constructor>[] chosenCtors, final Object[] explicitArgs) { // 創(chuàng)建 BeanWrapperImpl 對(duì)象 BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Constructor> constructorToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; // 確定參數(shù)值列表(argsToUse) if (explicitArgs != null) { argsToUse = explicitArgs; } else { Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { // 獲取已解析的構(gòu)造方法 constructorToUse = (Constructor>) mbd.resolvedConstructorOrFactoryMethod; if (constructorToUse != null && mbd.constructorArgumentsResolved) { // 獲取已解析的構(gòu)造方法參數(shù)列表 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { // 若 argsToUse 為空,則獲取未解析的構(gòu)造方法參數(shù)列表 argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { // 解析參數(shù)列表 argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve); } } if (constructorToUse == null) { boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); ConstructorArgumentValues resolvedValues = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); /* * 確定構(gòu)造方法參數(shù)數(shù)量,比如下面的配置: ** * * 此時(shí) minNrOfArgs = maxIndex + 1 = 2 + 1 = 3,除了計(jì)算 minNrOfArgs, * 下面的方法還會(huì)將 cargs 中的參數(shù)數(shù)據(jù)轉(zhuǎn)存到 resolvedValues 中 */ minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } // 獲取構(gòu)造方法列表 Constructor>[] candidates = chosenCtors; if (candidates == null) { Class> beanClass = mbd.getBeanClass(); try { candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Resolution of declared constructors on bean Class [" + beanClass.getName() + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } } // 按照構(gòu)造方法的訪問權(quán)限級(jí)別和參數(shù)數(shù)量進(jìn)行排序 AutowireUtils.sortConstructors(candidates); int minTypeDiffWeight = Integer.MAX_VALUE; Set* * * > ambiguousConstructors = null; LinkedList causes = null; for (Constructor> candidate : candidates) { Class>[] paramTypes = candidate.getParameterTypes(); /* * 下面的 if 分支的用途是:若匹配到到合適的構(gòu)造方法了,提前結(jié)束 for 循環(huán) * constructorToUse != null 這個(gè)條件比較好理解,下面分析一下條件 argsToUse.length > paramTypes.length: * 前面說到 AutowireUtils.sortConstructors(candidates) 用于對(duì)構(gòu)造方法進(jìn)行 * 排序,排序規(guī)則如下: * 1. 具有 public 訪問權(quán)限的構(gòu)造方法排在非 public 構(gòu)造方法前 * 2. 參數(shù)數(shù)量多的構(gòu)造方法排在前面 * * 假設(shè)現(xiàn)在有一組構(gòu)造方法按照上面的排序規(guī)則進(jìn)行排序,排序結(jié)果如下(省略參數(shù)名稱): * * 1. public Hello(Object, Object, Object) * 2. public Hello(Object, Object) * 3. public Hello(Object) * 4. protected Hello(Integer, Object, Object, Object) * 5. protected Hello(Integer, Object, Object) * 6. protected Hello(Integer, Object) * * argsToUse = [num1, obj2],可以匹配上的構(gòu)造方法2和構(gòu)造方法6。由于構(gòu)造方法2有 * 更高的訪問權(quán)限,所以沒理由不選他(盡管后者在參數(shù)類型上更加匹配)。由于構(gòu)造方法3 * 參數(shù)數(shù)量 < argsToUse.length,參數(shù)數(shù)量上不匹配,也不應(yīng)該選。所以 * argsToUse.length > paramTypes.length 這個(gè)條件用途是:在條件 * constructorToUse != null 成立的情況下,通過判斷參數(shù)數(shù)量與參數(shù)值數(shù)量 * (argsToUse.length)是否一致,來決定是否提前終止構(gòu)造方法匹配邏輯。 */ if (constructorToUse != null && argsToUse.length > paramTypes.length) { break; } /* * 構(gòu)造方法參數(shù)數(shù)量低于配置的參數(shù)數(shù)量,則忽略當(dāng)前構(gòu)造方法,并重試。比如 * argsToUse = [obj1, obj2, obj3, obj4],上面的構(gòu)造方法列表中, * 構(gòu)造方法1、2和3顯然不是合適選擇,忽略之。 */ if (paramTypes.length < minNrOfArgs) { continue; } ArgumentsHolder argsHolder; if (resolvedValues != null) { try { /* * 判斷否則方法是否有 ConstructorProperties 注解,若有,則取注解中的 * 值。比如下面的代碼: * * public class Persion { * private String name; * private Integer age; * * @ConstructorProperties(value = {"coolblog", "20"}) * public Persion(String name, Integer age) { * this.name = name; * this.age = age; * } * } */ String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); if (paramNames == null) { ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { /* * 獲取構(gòu)造方法參數(shù)名稱列表,比如有這樣一個(gè)構(gòu)造方法: * public Person(String name, int age, String sex) * * 調(diào)用 getParameterNames 方法返回 paramNames = [name, age, sex] */ paramNames = pnd.getParameterNames(candidate); } } /* * 創(chuàng)建參數(shù)值列表,返回 argsHolder 會(huì)包含進(jìn)行類型轉(zhuǎn)換后的參數(shù)值,比如下 * 面的配置: * * * * * Person 的成員變量 age 是 Integer 類型的,但由于在 Spring 配置中 * 只能配成 String 類型,所以這里要進(jìn)行類型轉(zhuǎn)換。 */ argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring); } catch (UnsatisfiedDependencyException ex) { if (this.beanFactory.logger.isTraceEnabled()) { this.beanFactory.logger.trace( "Ignoring constructor [" + candidate + "] of bean "" + beanName + "": " + ex); } if (causes == null) { causes = new LinkedList* * * (); } causes.add(ex); continue; } } else { if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } /* * 計(jì)算參數(shù)值(argsHolder.arguments)每個(gè)參數(shù)類型與構(gòu)造方法參數(shù)列表 * (paramTypes)中參數(shù)的類型差異量,差異量越大表明參數(shù)類型差異越大。參數(shù)類型差異 * 越大,表明當(dāng)前構(gòu)造方法并不是一個(gè)最合適的候選項(xiàng)。引入差異量(typeDiffWeight) * 變量目的:是將候選構(gòu)造方法的參數(shù)列表類型與參數(shù)值列表類型的差異進(jìn)行量化,通過量化 * 后的數(shù)值篩選出最合適的構(gòu)造方法。 * * 講完差異量,再來說說 mbd.isLenientConstructorResolution() 條件。 * 官方的解釋是:返回構(gòu)造方法的解析模式,有寬松模式(lenient mode)和嚴(yán)格模式 * (strict mode)兩種類型可選。具體的細(xì)節(jié)沒去研究,就不多說了。 */ int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); if (typeDiffWeight < minTypeDiffWeight) { constructorToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousConstructors = null; } /* * 如果兩個(gè)構(gòu)造方法與參數(shù)值類型列表之間的差異量一致,那么這兩個(gè)方法都可以作為 * 候選項(xiàng),這個(gè)時(shí)候就出現(xiàn)歧義了,這里先把有歧義的構(gòu)造方法放入 * ambiguousConstructors 集合中 */ else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) { if (ambiguousConstructors == null) { ambiguousConstructors = new LinkedHashSet >(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); } } // 若上面未能篩選出合適的構(gòu)造方法,這里將拋出 BeanCreationException 異常 if (constructorToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Could not resolve matching constructor " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)"); } /* * 如果 constructorToUse != null,且 ambiguousConstructors 也不為空,表明解析 * 出了多個(gè)的合適的構(gòu)造方法,此時(shí)就出現(xiàn)歧義了。Spring 不會(huì)擅自決定使用哪個(gè)構(gòu)造方法, * 所以拋出異常。 */ else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Ambiguous constructor matches found in bean "" + beanName + "" " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousConstructors); } if (explicitArgs == null) { /* * 緩存相關(guān)信息,比如: * 1. 已解析出的構(gòu)造方法對(duì)象 resolvedConstructorOrFactoryMethod * 2. 構(gòu)造方法參數(shù)列表是否已解析標(biāo)志 constructorArgumentsResolved * 3. 參數(shù)值列表 resolvedConstructorArguments 或 preparedConstructorArguments * * 這些信息可用在其他地方,用于進(jìn)行快捷判斷 */ argsHolderToUse.storeCache(mbd, constructorToUse); } } try { Object beanInstance; if (System.getSecurityManager() != null) { final Constructor> ctorToUse = constructorToUse; final Object[] argumentsToUse = argsToUse; beanInstance = AccessController.doPrivileged(new PrivilegedAction
上面的方法邏輯比較復(fù)雜,做了不少事情,該方法的核心邏輯是根據(jù)參數(shù)值類型篩選合適的構(gòu)造方法。解析出合適的構(gòu)造方法后,剩下的工作就是構(gòu)建 bean 對(duì)象了,這個(gè)工作交給了實(shí)例化策略去做。下面羅列一下這個(gè)方法的工作流程吧:
創(chuàng)建 BeanWrapperImpl 對(duì)象
解析構(gòu)造方法參數(shù),并算出 minNrOfArgs
獲取構(gòu)造方法列表,并排序
遍歷排序好的構(gòu)造方法列表,篩選合適的構(gòu)造方法
獲取構(gòu)造方法參數(shù)列表中每個(gè)參數(shù)的名稱
再次解析參數(shù),此次解析會(huì)將
計(jì)算構(gòu)造方法參數(shù)列表與參數(shù)值列表之間的類型差異量,以篩選出更為合適的構(gòu)造方法
緩存已篩選出的構(gòu)造方法以及參數(shù)值列表,若再次創(chuàng)建 bean 實(shí)例時(shí),可直接使用,無需再次進(jìn)行篩選
使用初始化策略創(chuàng)建 bean 對(duì)象
將 bean 對(duì)象放入 BeanWrapperImpl 對(duì)象中,并返回該對(duì)象
由上面的流程可以看得出,通過構(gòu)造方法自動(dòng)注入的方式構(gòu)造 bean 對(duì)象的過程還是很復(fù)雜的。為了看懂這個(gè)流程,我進(jìn)行了多次調(diào)試,算是勉強(qiáng)弄懂大致邏輯。由于時(shí)間有限,我并未能詳細(xì)分析 autowireConstructor 方法及其所調(diào)用的一些方法,比如 resolveConstructorArguments、 autowireConstructor 等。關(guān)于這些方法,這里只寫了個(gè)大概,有興趣的朋友自己去探索吧。
2.3 通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象看完了上面冗長(zhǎng)的邏輯,本節(jié)來看點(diǎn)輕松的吧 - 通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象。如下:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; // if 條件分支里的一大坨是 Java 安全相關(guān)的代碼,可以忽略,直接看 else 分支 if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged(new PrivilegedAction
上面就是通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象的過程,比較簡(jiǎn)單,就不多說了。最后我們?cè)賮砜纯春?jiǎn)單看看通過無參構(gòu)造方法剛創(chuàng)建 bean 對(duì)象的代碼(通過 CGLIB 創(chuàng)建 bean 對(duì)象的方式就不看了)是怎樣的,如下:
public staticT instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { // 設(shè)置構(gòu)造方法為可訪問 ReflectionUtils.makeAccessible(ctor); // 通過反射創(chuàng)建 bean 實(shí)例,這里的 args 是一個(gè)沒有元素的空數(shù)組 return ctor.newInstance(args); } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
到這里,終于看到了創(chuàng)建 bean 對(duì)象的代碼了。在經(jīng)歷層層調(diào)用后,我們總算是追到了調(diào)用棧的最深處??吹竭@里,大家可以休息一下了,本文也差不多要結(jié)束了。好了,最后再容我多啰嗦一會(huì),往下看。
3.寫在最后寫到這里,我也算是松了一口氣,終于快寫完了。這篇文章寫起來感覺挺不容易的,原因是 createBeanInstance 及其調(diào)用的方法是在太多了,而且很多方法邏輯還是比較復(fù)雜的,尤其是 autowireConstructor 中調(diào)用的一些方法。autowireConstructor 中調(diào)用的方法我基本上都看了一遍,但并非全部都弄懂了,有些方法只是知道個(gè)大概。所以,這篇文章寫的我挺糾結(jié)的,生怕有些地方分析的不對(duì)。由于我后續(xù)還有很多東西要看,以至于我暫時(shí)沒法抽出大量的時(shí)間去詳細(xì)閱讀 Spring 的源碼。所以如果上面的分析有不對(duì)的地方,歡迎指正,我會(huì)虛心聽之。如果這些不對(duì)的地方給你造成了困擾,實(shí)在很抱歉,抱歉。
好了,本篇文章先到這里。謝謝閱讀!
參考《Spring 源碼深度解析》- 郝佳
附錄:Spring 源碼分析文章列表 Ⅰ. IOC更新時(shí)間 | 標(biāo)題 |
---|---|
2018-05-30 | Spring IOC 容器源碼分析系列文章導(dǎo)讀 |
2018-06-01 | Spring IOC 容器源碼分析 - 獲取單例 bean |
2018-06-04 | Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過程 |
2018-06-06 | Spring IOC 容器源碼分析 - 創(chuàng)建原始 bean 對(duì)象 |
2018-06-08 | Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法 |
2018-06-11 | Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對(duì)象 |
2018-06-11 | Spring IOC 容器源碼分析 - 余下的初始化工作 |
更新時(shí)間 | 標(biāo)題 |
---|---|
2018-06-17 | Spring AOP 源碼分析系列文章導(dǎo)讀 |
2018-06-20 | Spring AOP 源碼分析 - 篩選合適的通知器 |
2018-06-20 | Spring AOP 源碼分析 - 創(chuàng)建代理對(duì)象 |
2018-06-22 | Spring AOP 源碼分析 - 攔截器鏈的執(zhí)行過程 |
更新時(shí)間 | 標(biāo)題 |
---|---|
2018-06-29 | Spring MVC 原理探秘 - 一個(gè)請(qǐng)求的旅行過程 |
2018-06-30 | Spring MVC 原理探秘 - 容器的創(chuàng)建過程 |
本文在知識(shí)共享許可協(xié)議 4.0 下發(fā)布,轉(zhuǎn)載需在明顯位置處注明出處
作者:coolblog.xyz
本文同步發(fā)布在我的個(gè)人博客:http://www.coolblog.xyz
本作品采用知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議進(jìn)行許可。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69664.html
摘要:實(shí)例化時(shí),發(fā)現(xiàn)又依賴于。一些緩存的介紹在進(jìn)行源碼分析前,我們先來看一組緩存的定義??墒强赐暝创a后,我們似乎仍然不知道這些源碼是如何解決循環(huán)依賴問題的。 1. 簡(jiǎn)介 本文,我們來看一下 Spring 是如何解決循環(huán)依賴問題的。在本篇文章中,我會(huì)首先向大家介紹一下什么是循環(huán)依賴。然后,進(jìn)入源碼分析階段。為了更好的說明 Spring 解決循環(huán)依賴的辦法,我將會(huì)從獲取 bean 的方法getB...
摘要:簡(jiǎn)介本篇文章是容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是方法,該方法用于對(duì)已完成屬性填充的做最后的初始化工作。后置處理器是拓展點(diǎn)之一,通過實(shí)現(xiàn)后置處理器接口,我們就可以插手的初始化過程。 1. 簡(jiǎn)介 本篇文章是Spring IOC 容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是 initializeBean 方法,該方法用于對(duì)已完成屬性填充的 bean 做最...
摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...
摘要:源碼分析源碼一覽本節(jié),我們先來看一下填充屬性的方法,即。所有的屬性值是在方法中統(tǒng)一被注入到對(duì)象中的。檢測(cè)是否存在與相關(guān)的或。這樣可以在很大程度上降低源碼分析的難度。若候選項(xiàng)是非類型,則表明已經(jīng)完成了實(shí)例化,此時(shí)直接返回即可。 1. 簡(jiǎn)介 本篇文章,我們來一起了解一下 Spring 是如何將配置文件中的屬性值填充到 bean 對(duì)象中的。我在前面幾篇文章中介紹過 Spring 創(chuàng)建 bea...
摘要:關(guān)于創(chuàng)建實(shí)例的過程,我將會(huì)分幾篇文章進(jìn)行分析。源碼分析創(chuàng)建實(shí)例的入口在正式分析方法前,我們先來看看方法是在哪里被調(diào)用的。時(shí),表明方法不存在,此時(shí)拋出異常。該變量用于表示是否提前暴露單例,用于解決循環(huán)依賴。 1. 簡(jiǎn)介 在上一篇文章中,我比較詳細(xì)的分析了獲取 bean 的方法,也就是getBean(String)的實(shí)現(xiàn)邏輯。對(duì)于已實(shí)例化好的單例 bean,getBean(String) ...
閱讀 3547·2021-11-17 17:01
閱讀 3951·2021-11-08 13:12
閱讀 2508·2021-10-08 10:04
閱讀 735·2021-09-29 09:35
閱讀 1450·2021-09-26 10:12
閱讀 2116·2021-09-07 09:58
閱讀 1985·2019-08-30 15:55
閱讀 2165·2019-08-30 13:14