【spring源碼分析】IOC容器初始化(十)

前言:前文【spring源碼分析】IOC容器初始化(九)中分析了AbstractAutowireCapableBeanFactory#createBeanInstance方法中經過工廠方法建立bean對象的流程,這裏接着分析createBeanInstance方法中的剩餘流程。html


直接看createBeanInstance中剩餘的流程:spring

 1 // AbstractAutowireCapableBeanFactory
 2 boolean resolved = false;
 3         boolean autowireNecessary = false;
 4         if (args == null) {
 5             // 作同步
 6             synchronized (mbd.constructorArgumentLock) {
 7                 // 若是已緩存的解析構造函數或者工廠方法不爲null,則能夠利用構造函數解析
 8                 // 由於須要根據參數確認到底使用哪一個構造函數,該過程比較消耗性能,因此採用緩存機制
 9                 if (mbd.resolvedConstructorOrFactoryMethod != null) {
10                     resolved = true;
11                     autowireNecessary = mbd.constructorArgumentsResolved;
12                 }
13             }
14         }
15         // 已經解析好了,直接注入便可
16         if (resolved) {
17             // autowire自動注入,調用構造函數自動注入
18             if (autowireNecessary) {
19                 return autowireConstructor(beanName, mbd, null, null);
20             } else {
21                 // 使用默認構造函數構造
22                 return instantiateBean(beanName, mbd);
23             }
24         }
25 
26         // Need to determine the constructor...
27         // 肯定解析的構造函數
28         // 主要是檢查已經註冊的SmartInstantiationAwareBeanPostProcessor
29         Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
30         // 肯定構造方法進行bean建立
31         if (ctors != null ||
32                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
33                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
34             return autowireConstructor(beanName, mbd, ctors, args);
35         }
36 
37         // 有參數,又沒有獲取到構造方法,則只能調用無參構造方法來建立實例
38         // 這是一個兜底的方法
39         // No special handling: simply use no-arg constructor.
40         return instantiateBean(beanName, mbd);

分析:緩存

剩餘流程還剩下兩大分支:構造函數自動注入初始化bean和默認構造函數初始化bean。安全

#1 AbstractAutowireCapableBeanFactory#autowireConstructorapp

1     protected BeanWrapper autowireConstructor(
2             String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
3 
4         return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
5     }

能夠看到這裏仍是委託給ConstructorResolver來執行的:less

  1 public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
  2                                            @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
  3 
  4         // 封裝BeanWrapperImpl並完成初始化
  5         BeanWrapperImpl bw = new BeanWrapperImpl();
  6         this.beanFactory.initBeanWrapper(bw);
  7 
  8         // 獲取constructorToUse、argsHolderToUse、argsToUse屬性
  9         Constructor<?> constructorToUse = null; // 構造函數
 10         ArgumentsHolder argsHolderToUse = null; // 構造參數
 11         Object[] argsToUse = null;  // 構造參數
 12 
 13         // 肯定構造參數
 14         // 若是getBean()已傳遞,則直接使用
 15         if (explicitArgs != null) {
 16             argsToUse = explicitArgs;
 17         } else {
 18             // 嘗試從緩存中獲取
 19             Object[] argsToResolve = null;
 20             // 同步
 21             synchronized (mbd.constructorArgumentLock) {
 22                 // 緩存中的構造函數或工廠方法
 23                 constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
 24                 if (constructorToUse != null && mbd.constructorArgumentsResolved) {
 25                     // Found a cached constructor...
 26                     // 緩存中的構造參數
 27                     argsToUse = mbd.resolvedConstructorArguments;
 28                     if (argsToUse == null) {
 29                         // 獲取緩存中的構造函數參數 包括可見字段
 30                         argsToResolve = mbd.preparedConstructorArguments;
 31                     }
 32                 }
 33             }
 34             // 緩存中存在,則解析存儲在BeanDefinition中的參數
 35             // 如給定方法的構造函數 f(int,int),則經過此方法後就會把配置文件中的("1","1")轉換爲 (1,1)
 36             // 緩存中的值多是原始值也有多是最終值
 37             if (argsToResolve != null) {
 38                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
 39             }
 40         }
 41 
 42         // 沒有緩存,則嘗試從配置文件中獲取參數
 43         if (constructorToUse == null || argsToUse == null) {
 44             // Take specified constructors, if any.
 45             Constructor<?>[] candidates = chosenCtors;
 46             // 若是chosenCtors未傳入,則獲取構造方法
 47             if (candidates == null) {
 48                 Class<?> beanClass = mbd.getBeanClass();
 49                 try {
 50                     candidates = (mbd.isNonPublicAccessAllowed() ?
 51                             beanClass.getDeclaredConstructors() : beanClass.getConstructors());
 52                 } catch (Throwable ex) {
 53                     throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 54                                                     "Resolution of declared constructors on bean Class [" + beanClass.getName() +
 55                                                             "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
 56                 }
 57             }
 58             // 建立bean
 59             if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
 60                 Constructor<?> uniqueCandidate = candidates[0];
 61                 if (uniqueCandidate.getParameterCount() == 0) {
 62                     synchronized (mbd.constructorArgumentLock) {
 63                         mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
 64                         mbd.constructorArgumentsResolved = true;
 65                         mbd.resolvedConstructorArguments = EMPTY_ARGS;
 66                     }
 67                     bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
 68                     return bw;
 69                 }
 70             }
 71 
 72             // 是否須要解析構造器
 73             // Need to resolve the constructor.
 74             boolean autowiring = (chosenCtors != null ||
 75                     mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
 76             // 用於承載解析後的構造函數參數值
 77             ConstructorArgumentValues resolvedValues = null;
 78 
 79             int minNrOfArgs;
 80             if (explicitArgs != null) {
 81                 minNrOfArgs = explicitArgs.length;
 82             } else {
 83                 // 從BeanDefinition中獲取構造參數,也就是從配置文件中提取構造參數
 84                 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
 85                 resolvedValues = new ConstructorArgumentValues();
 86                 // 解析構造函數的參數
 87                 // 將該bean的構造函數參數解析爲resolvedValues對象,其中會涉及到其餘bean
 88                 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
 89             }
 90 
 91             // 對構造函數進行排序處理
 92             // public構造函數優先,參數數量降序,非public構造函數參數數量降序
 93             AutowireUtils.sortConstructors(candidates);
 94 
 95             // 最小參數類型權重
 96             int minTypeDiffWeight = Integer.MAX_VALUE;
 97             Set<Constructor<?>> ambiguousConstructors = null;
 98             LinkedList<UnsatisfiedDependencyException> causes = null;
 99 
100             // 遍歷全部構造函數
101             for (Constructor<?> candidate : candidates) {
102                 // 獲取該構造函數的參數類型
103                 Class<?>[] paramTypes = candidate.getParameterTypes();
104 
105                 // 若是已經找到選用的構造函數且須要的參數個數大於當前構造函數參數個數,則break
106                 if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
107                     // Already found greedy constructor that can be satisfied ->
108                     // do not look any further, there are only less greedy constructors left.
109                     break;
110                 }
111                 // 參數個數不等,繼續循環
112                 if (paramTypes.length < minNrOfArgs) {
113                     continue;
114                 }
115 
116                 // 參數持有者ArgumentsHolder對象
117                 ArgumentsHolder argsHolder;
118                 if (resolvedValues != null) {
119                     try {
120                         // 註釋上獲取參數名稱
121                         String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
122                         if (paramNames == null) {
123                             // 獲取構造函數、方法參數的探測器
124                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
125                             if (pnd != null) {
126                                 // 經過探測器獲取構造函數的參數名稱
127                                 paramNames = pnd.getParameterNames(candidate);
128                             }
129                         }
130                         // 根據構造函數和構造參數,建立參數持有者ArgumentsHolder對象
131                         argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
132                                                          getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
133                     } catch (UnsatisfiedDependencyException ex) {
134                         if (logger.isTraceEnabled()) {
135                             logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
136                         }
137                         // Swallow and try next constructor.
138                         if (causes == null) {
139                             causes = new LinkedList<>();
140                         }
141                         // 若產生UnsatisfiedDependencyException異常,則添加到causes中
142                         causes.add(ex);
143                         continue;
144                     }
145                 } else {
146                     // Explicit arguments given -> arguments length must match exactly.
147                     // 構造函數中沒有參數,則continue
148                     if (paramTypes.length != explicitArgs.length) {
149                         continue;
150                     }
151                     // 根據explicitArgs建立ArgumentsHolder對象
152                     argsHolder = new ArgumentsHolder(explicitArgs);
153                 }
154 
155                 // isLenientConstructorResolution 判斷解析構造函數的時候是否以寬鬆模式仍是嚴格模式
156                 // 嚴格模式:解析構造函數時,必須全部的都須要匹配,不然拋出異常
157                 // 寬鬆模式:使用具備"最接近的模式"進行匹配
158                 // typeDiffWeight:類型差別權重
159                 int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
160                         argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
161                 // Choose this constructor if it represents the closest match.
162                 // 若是它表明着當前最接近的匹配則選擇其做爲構造函數
163                 if (typeDiffWeight < minTypeDiffWeight) {
164                     constructorToUse = candidate;
165                     argsHolderToUse = argsHolder;
166                     argsToUse = argsHolder.arguments;
167                     minTypeDiffWeight = typeDiffWeight;
168                     ambiguousConstructors = null;
169                 } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
170                     if (ambiguousConstructors == null) {
171                         ambiguousConstructors = new LinkedHashSet<>();
172                         ambiguousConstructors.add(constructorToUse);
173                     }
174                     ambiguousConstructors.add(candidate);
175                 }
176             }
177 
178             // 沒有可執行的工廠方法,則拋出異常
179             if (constructorToUse == null) {
180                 if (causes != null) {
181                     UnsatisfiedDependencyException ex = causes.removeLast();
182                     for (Exception cause : causes) {
183                         this.beanFactory.onSuppressedException(cause);
184                     }
185                     throw ex;
186                 }
187                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
188                                                 "Could not resolve matching constructor " +
189                                                         "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
190             } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
191                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
192                                                 "Ambiguous constructor matches found in bean '" + beanName + "' " +
193                                                         "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
194                                                         ambiguousConstructors);
195             }
196 
197             if (explicitArgs == null && argsHolderToUse != null) {
198                 // 將解析的構造函數加入緩存
199                 argsHolderToUse.storeCache(mbd, constructorToUse);
200             }
201         }
202         // 建立bean對象,並設置到BeanWrapperImpl中
203         Assert.state(argsToUse != null, "Unresolved constructor arguments");
204         bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
205         return bw;
206     }

分析:ide

該函數可簡單理解爲是帶有參數的構造方法來進行bean的初始化。能夠看到該函數與【spring源碼分析】IOC容器初始化(九)中分析的instantiateUsingFactoryMethod函數同樣方法體都很是的大,若是理解了instantiateUsingFactoryMethod中的初始化過程,其實對autowireConstructor函數的理解就不是很難了,該函數主要是肯定構造函數參數、構造函數而後調用相應的初始化策略對bean進行初始化,其大部分邏輯都與instantiateUsingFactoryMethod函數一致,若有不明之處,請移步到上篇文章,但需但需注意其中的instantiate是不同的,這裏咱們來看下該函數。函數

instantiate

 1 private Object instantiate(
 2             String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {
 3 
 4         try {
 5             InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
 6             if (System.getSecurityManager() != null) {
 7                 return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
 8                                                              strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse),
 9                                                      this.beanFactory.getAccessControlContext());
10             } else {
11                 return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
12             }
13         } catch (Throwable ex) {
14             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
15                                             "Bean instantiation via constructor failed", ex);
16         }
17     }

分析:源碼分析

這裏對bean進行實例化,會委託SimpleInstantiationStrategy#instantiate方法進行實現:性能

 1 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
 2                               final Constructor<?> ctor, Object... args) {
 3         // 沒有覆蓋,則直接使用反射實例化便可
 4         if (!bd.hasMethodOverrides()) {
 5             if (System.getSecurityManager() != null) {
 6                 // use own privileged to change accessibility (when security is on)
 7                 // 設置構造方法,可訪問
 8                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 9                     ReflectionUtils.makeAccessible(ctor);
10                     return null;
11                 });
12             }
13             // 經過BeanUtils直接使用構造器對象實例化bean對象
14             return BeanUtils.instantiateClass(ctor, args);
15         } else {
16             // CGLIB建立bean對象
17             return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
18         }
19     }

分析:

  • 若是該bean沒有配置lookup-method、replace-method或者@LookUp註解,則直接經過反射的方式實例化bean對象便可。
  • 若是存在覆蓋,則須要使用CGLIB進行動態代理,由於在建立代理的同時可將動態方法織入類中。

#1 經過反射實例化bean對象

 1 // BeanUtils
 2 public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
 3         Assert.notNull(ctor, "Constructor must not be null");
 4         try {
 5             // 設置構造方法,可訪問
 6             ReflectionUtils.makeAccessible(ctor);
 7             // 使用構造方法建立對象
 8             if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
 9                 return KotlinDelegate.instantiateClass(ctor, args);
10             } else {
11                 Class<?>[] parameterTypes = ctor.getParameterTypes();
12                 Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
13                 Object[] argsWithDefaultValues = new Object[args.length];
14                 for (int i = 0; i < args.length; i++) {
15                     if (args[i] == null) {
16                         Class<?> parameterType = parameterTypes[i];
17                         argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
18                     } else {
19                         argsWithDefaultValues[i] = args[i];
20                     }
21                 }
22                 return ctor.newInstance(argsWithDefaultValues);
23             }
24         }
25         // 各類異常,最終統一拋出BeanInstantiationException異常
26         catch (InstantiationException ex) {
27             throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
28         } catch (IllegalAccessException ex) {
29             throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
30         } catch (IllegalArgumentException ex) {
31             throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
32         } catch (InvocationTargetException ex) {
33             throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
34         }
35     }

#2 經過CGLIB建立Bean對象,這裏會經過其子類實現

1 // CglibSubclassingInstantiationStrategy
2     protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
3                                                     @Nullable Constructor<?> ctor, Object... args) {
4 
5         // Must generate CGLIB subclass...
6         // 經過CGLIB生成一個子類對象
7         return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
8     }

分析:

首先建立一個CglibSubclassCreator對象,而後調用其instantiate進行初始化bean對象。

CglibSubclassingInstantiationStrategy#instantiate

 1 public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
 2             // 經過cglib建立一個代理類
 3             Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
 4             Object instance;
 5             // 沒有構造器,經過BeanUtils使用默認構造器建立一個bean實例
 6             if (ctor == null) {
 7                 instance = BeanUtils.instantiateClass(subclass);
 8             } else {
 9                 try {
10                     // 獲取代理類對應的構造器對象,並實例化bean
11                     Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
12                     instance = enhancedSubclassConstructor.newInstance(args);
13                 } catch (Exception ex) {
14                     throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
15                                                          "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
16                 }
17             }
18             // SPR-10785: set callbacks directly on the instance instead of in the
19             // enhanced class (via the Enhancer) in order to avoid memory leaks.
20             // 爲了不memory leaks異常,直接在bean實例上設置回調對象
21             Factory factory = (Factory) instance;
22             factory.setCallbacks(new Callback[]{NoOp.INSTANCE,
23                                                 new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
24                                                 new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
25             return instance;
26         }

分析:

這裏是經過CGLIB來建立bean對象,這部份內容後續分析AOP的時候再詳細分析。

至此經過構造函數自動注入初始化bean對象分析完畢,下面來看使用默認構造函數初始化bean。

#2 AbstractAutowireCapableBeanFactory#instantiateBean

 1 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
 2         try {
 3             Object beanInstance;
 4             final BeanFactory parent = this;
 5             // 安全模式
 6             if (System.getSecurityManager() != null) {
 7                 // 得到InstantiationStrategy對象,並使用它建立bean對象
 8                 beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent),
 9                                                              getAccessControlContext());
10             } else {
11                 // 得到InstantiationStrategy對象,並使用它建立bean對象
12                 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
13             }
14             // 封裝BeanWrapperImpl,並完成初始化
15             BeanWrapper bw = new BeanWrapperImpl(beanInstance);
16             initBeanWrapper(bw);
17             return bw;
18         } catch (Throwable ex) {
19             throw new BeanCreationException(
20                     mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
21         }
22     }

分析:

在經歷過前面大方法體的分析後,再看該方法就簡單得多了,該方法不須要構造參數,因此不須要進行復雜的肯定構造參數、構造器等步驟,主要經過instantiate實例化對象後,注入BeanWrapper中,而後初始化BeanWrapper。

SimpleInstantiationStrategy#instantiate

 1 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
 2         // Don't override the class with CGLIB if no overrides.
 3         // 沒有覆蓋,直接使用反射實例化便可
 4         if (!bd.hasMethodOverrides()) {
 5             Constructor<?> constructorToUse;
 6             synchronized (bd.constructorArgumentLock) {
 7                 // 得到構造方法 constructorToUse
 8                 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
 9                 if (constructorToUse == null) {
10                     final Class<?> clazz = bd.getBeanClass();
11                     // 若是是接口,則拋出異常
12                     if (clazz.isInterface()) {
13                         throw new BeanInstantiationException(clazz, "Specified class is an interface");
14                     }
15                     try {
16                         // 從clazz中,得到構造方法
17                         if (System.getSecurityManager() != null) {
18                             constructorToUse = AccessController.doPrivileged(
19                                     (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
20                         } else {
21                             constructorToUse = clazz.getDeclaredConstructor();
22                         }
23                         // 標記resolvedConstructorOrFactoryMethod屬性
24                         bd.resolvedConstructorOrFactoryMethod = constructorToUse;
25                     } catch (Throwable ex) {
26                         throw new BeanInstantiationException(clazz, "No default constructor found", ex);
27                     }
28                 }
29             }
30             // 經過BeanUtils直接使用構造器實例化bean對象
31             return BeanUtils.instantiateClass(constructorToUse);
32         } else {
33             // 經過CGLIB建立子類對象
34             // Must generate CGLIB subclass.
35             return instantiateWithMethodInjection(bd, beanName, owner);
36         }
37     }

分析:

該方法也比較簡單,經過判斷BeanDefinition是否有覆蓋方法進行分支:經過反射或CGLIB來建立bean實例。

最後,若是以上分支還不知足,則會經過instantiateBean方法兜底來完成bean的實例化。

總結

終於把AbstractAutowireCapableBeanFactory#createBeanInstance方法大體分析完了,該方法就是選擇合適的實例化策略來爲bean建立實例對象,具體策略有:

  • Supplier回調方式。
  • 工廠方法初始化。
  • 構造函數自動注入初始化。
  • 默認構造函數初始化。

其中工廠方法初始化與構造函數自動注入初始化方式很是複雜,須要大量的經從來肯定構造函數和構造參數。

至此createBeanInstance過程已經分析完畢,下面將介紹doCreateBean的其餘處理流程。


by Shawn Chen,2019.04.25,下午。

相關文章
相關標籤/搜索