日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring IOC 容器源码分析 - 创建原始 bean 对象

發(fā)布時(shí)間:2025/3/21 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring IOC 容器源码分析 - 创建原始 bean 对象 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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í)行流程,如下:

  • 檢測(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ù)雜,需要大家耐心閱讀。代碼如下:

    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è)方法的工作流程吧:

  • 創(chuàng)建 BeanWrapperImpl 對(duì)象
  • 解析構(gòu)造方法參數(shù),并算出 minNrOfArgs
  • 獲取構(gòu)造方法列表,并排序
  • 遍歷排序好的構(gòu)造方法列表,篩選合適的構(gòu)造方法
  • 獲取構(gòu)造方法參數(shù)列表中每個(gè)參數(shù)的名稱
  • 再次解析參數(shù),此次解析會(huì)將value 屬性值進(jìn)行類型轉(zhuǎn)換,由 String 轉(zhuǎn)為合適的類型。
  • 計(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ì)象。如下:

    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

    更新時(shí)間標(biāo)題
    2018-05-30Spring IOC 容器源碼分析系列文章導(dǎo)讀
    2018-06-01Spring IOC 容器源碼分析 - 獲取單例 bean
    2018-06-04Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過程
    2018-06-06Spring IOC 容器源碼分析 - 創(chuàng)建原始 bean 對(duì)象
    2018-06-08Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法
    2018-06-11Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對(duì)象
    2018-06-11Spring IOC 容器源碼分析 - 余下的初始化工作

    ?Ⅱ. AOP

    更新時(shí)間標(biāo)題
    2018-06-17Spring AOP 源碼分析系列文章導(dǎo)讀
    2018-06-20Spring AOP 源碼分析 - 篩選合適的通知器
    2018-06-20Spring AOP 源碼分析 - 創(chuàng)建代理對(duì)象
    2018-06-22Spring AOP 源碼分析 - 攔截器鏈的執(zhí)行過程

    ?Ⅲ. MVC

    更新時(shí)間標(biāo)題
    2018-06-29Spring MVC 原理探秘 - 一個(gè)請(qǐng)求的旅行過程
    2018-06-30Spring 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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人精品视频网站 | 色综合久久精品亚洲国产 | 日韩免费在线视频 | 日韩精品免费 | www.xxxxx日本| 亚洲免费网站在线观看 | 欧美日韩午夜爽爽 | 色猫咪av在线 | 97久久久久 | 黄色网页免费观看 | 欧美精品久久久久性色 | 亚洲免费观看高清完整 | 337p亚洲精品色噜噜狠狠 | 欧美男同又粗又长又大 | 欧美亚洲第一区 | 38在线视频 | 中文字幕乱码无码人妻系列蜜桃 | 国产超91 | 日本欧美一区二区 | 99视频 | 少妇av在线 | 黄av资源| 悟空影视大全免费高清观看在线 | free性欧美hd另类| 一区二区中文在线 | 给我免费观看片在线电影的 | 天天爽夜夜爽视频 | 日韩精品无码一区二区三区久久久 | 亚洲男人天堂2017 | 人人艹在线观看 | 香港三级韩国三级日本三级 | 欧美一区二不卡视频 | 午夜精品一区二区三区在线观看 | 老司机在线观看视频 | 伦理av在线 | 韩漫动漫免费大全在线观看 | 成年人在线免费 | 久久中出 | 精品国产欧美一区二区 | 久久女人网 | 久久久久人妻精品一区二区三区 | 狠狠干在线 | 国产成人精品影院 | 国产视频99| 日韩av手机在线免费观看 | 精品人妻一区二区三区在线视频 | 警察高h荡肉呻吟男男 | 亚洲欧美在线免费观看 | 最新天堂在线视频 | 超碰人人在线观看 | 99精品99| 性欧美一区二区 | 国产精品无码人妻一区二区在线 | 天堂网2014av| 中日一级片 | 蜜桃一区二区 | 国产精品一区在线观看你懂的 | 在线一区二区三区 | 日韩欧美亚洲综合 | 性色视频在线观看 | av网址观看 | 日本无翼乌邪恶大全彩h | 一级免费毛片 | 国产一级一区 | 性感少妇在线观看 | 日韩在线一二三区 | 婷婷调教口舌奴ⅴk | 自拍偷拍av | 末路1997全集免费观看完整版 | 亚洲国产成人精品无码区99 | 淫片网站 | 精品人妻一区二区三区日产乱码卜 | 国产又黄又嫩又滑又白 | 久久久一区二区三区四区 | 成人啪啪18免费游戏链接 | 亚洲精品18 | 欧美视频三区 | 黑人操亚洲女人 | 日韩在线91 | 日韩永久免费 | 亚洲av永久无码精品一区二区国产 | av手机 | 国产成人精品av久久 | 人操人爽 | 殴美黄色大片 | 欧美囗交做爰视频 | 国产欧美精品在线观看 | 国产精久久久 | 日韩久久影视 | 懂色一区二区三区 | 这里精品 | 亚洲福利视频网站 | 日韩福利在线视频 | 精品在线播放 | 国产成人午夜精品无码区久久 | 好大好爽好舒服 | 99精品视频免费看 | 波多野结衣视频在线观看 | 91射|