javascript
Spring IOC 容器源码分析 - 创建原始 bean 对象
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 → ↓
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 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 配置文件中* 是否配置了 <construct-arg/>* 條件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í)行流程,如下:
這里有三種構(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ù)雜,需要大家耐心閱讀。代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | 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ù)量,比如下面的配置:* <bean id="persion" class="xyz.coolblog.autowire.Person">* <constructor-arg index="0" value="xiaoming"/>* <constructor-arg index="1" value="1"/>* <constructor-arg index="2" value="man"/>* </bean>** 此時(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<Constructor<?>> ambiguousConstructors = null;LinkedList<UnsatisfiedDependencyException> 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ù)值,比如下* 面的配置:** <bean id="persion" class="xyz.coolblog.autowire.Person">* <constructor-arg name="name" value="xiaoming"/>* <constructor-arg name="age" value="1"/>* <constructor-arg name="sex" value="man"/>* </bean>** 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<UnsatisfiedDependencyException>();}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<Constructor<?>>();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<Object>() {@Overridepublic Object run() {return beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse);}}, beanFactory.getAccessControlContext());}else {/** 調(diào)用實(shí)例化策略創(chuàng)建實(shí)例,默認(rèn)情況下使用反射創(chuàng)建實(shí)例。如果 bean 的配置信息中* 包含 lookup-method 和 replace-method,則通過 CGLIB 增強(qiáng) bean 實(shí)例*/beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);}// 設(shè)置 beanInstance 到 BeanWrapperImpl 對(duì)象中bw.setBeanInstance(beanInstance);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean instantiation via constructor failed", ex);} } |
上面的方法邏輯比較復(fù)雜,做了不少事情,該方法的核心邏輯是根據(jù)參數(shù)值類型篩選合適的構(gòu)造方法。解析出合適的構(gòu)造方法后,剩下的工作就是構(gòu)建 bean 對(duì)象了,這個(gè)工作交給了實(shí)例化策略去做。下面羅列一下這個(gè)方法的工作流程吧:
由上面的流程可以看得出,通過構(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ì)象。如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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<Object>() {@Overridepublic Object run() {return getInstantiationStrategy().instantiate(mbd, beanName, parent);}}, getAccessControlContext());}else {/** 調(diào)用實(shí)例化策略創(chuàng)建實(shí)例,默認(rèn)情況下使用反射創(chuàng)建對(duì)象。如果 bean 的配置信息中* 包含 lookup-method 和 replace-method,則通過 CGLIB 創(chuàng)建 bean 對(duì)象*/beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);}// 創(chuàng)建 BeanWrapperImpl 對(duì)象BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);} }public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {// 檢測(cè) bean 配置中是否配置了 lookup-method 或 replace-method,若配置了,則需使用 CGLIB 構(gòu)建 bean 對(duì)象if (bd.getMethodOverrides().isEmpty()) {Constructor<?> constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {final Class<?> clazz = bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {if (System.getSecurityManager() != null) {constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {@Overridepublic Constructor<?> run() throws Exception {return clazz.getDeclaredConstructor((Class[]) null);}});}else {// 獲取默認(rèn)構(gòu)造方法constructorToUse = clazz.getDeclaredConstructor((Class[]) null);}// 設(shè)置 resolvedConstructorOrFactoryMethodbd.resolvedConstructorOrFactoryMethod = constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, "No default constructor found", ex);}}}// 通過無參構(gòu)造方法創(chuàng)建 bean 對(duì)象return BeanUtils.instantiateClass(constructorToUse);}else {// 使用 GCLIG 創(chuàng)建 bean 對(duì)象return instantiateWithMethodInjection(bd, beanName, owner);} } |
上面就是通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象的過程,比較簡(jiǎn)單,就不多說了。最后我們?cè)賮砜纯春?jiǎn)單看看通過無參構(gòu)造方法剛創(chuàng)建 bean 對(duì)象的代碼(通過 CGLIB 創(chuàng)建 bean 對(duì)象的方式就不看了)是怎樣的,如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public static <T> T instantiateClass(Constructor<T> 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
| 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 容器源碼分析 - 余下的初始化工作 |
?Ⅱ. AOP
| 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í)行過程 |
?Ⅲ. MVC
| 2018-06-29 | Spring MVC 原理探秘 - 一個(gè)請(qǐng)求的旅行過程 |
| 2018-06-30 | Spring MVC 原理探秘 - 容器的創(chuàng)建過程 |
- 本文鏈接:?https://www.tianxiaobo.com/2018/06/06/Spring-IOC-容器源碼分析-創(chuàng)建原始-bean-對(duì)象/
from:?http://www.tianxiaobo.com/2018/06/06/Spring-IOC-%E5%AE%B9%E5%99%A8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E5%88%9B%E5%BB%BA%E5%8E%9F%E5%A7%8B-bean-%E5%AF%B9%E8%B1%A1/?
總結(jié)
以上是生活随笔為你收集整理的Spring IOC 容器源码分析 - 创建原始 bean 对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring IOC 容器源码分析 -
- 下一篇: Spring IOC 容器源码分析 -