該系列文章是本人在學習 Spring 的過程當中總結下來的,裏面涉及到相關源碼,可能對讀者不太友好,請結合個人源碼註釋 Spring 源碼分析 GitHub 地址 進行閱讀html
Spring 版本:5.1.14.RELEASEjava
開始閱讀這一系列文章以前,建議先查看《深刻了解 Spring IoC(面試題)》這一篇文章git
該系列其餘文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》github
當咱們顯示或者隱式地調用AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的加載,在《開啓 Bean 的加載》文章中分析了整個加載過程。面試
對於不一樣做用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程當中,須要先獲取其 Class 對象,而後經過構造方法建立一個實例對象(反射機制),再進行後續的屬性填充和初始化工做。整個的實例化過程很是複雜,由於須要找到最匹配的構造方法,還須要找到該方法的入參,因此會有各類處理,本文將會分析建立 Bean 過程當中的實例化階段。spring
先來回顧一下建立 Bean 過程當中實例化階段對應的代碼:數組
// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法 // Instantiate the bean. /** * <1> Bean 的實例化階段,會將 Bean 的實例對象封裝成 {@link BeanWrapperImpl} 包裝對象 * BeanWrapperImpl 承擔的角色: * 1. Bean 實例的包裝 * 2. {@link org.springframework.beans.PropertyAccessor} 屬性編輯器 * 3. {@link org.springframework.beans.PropertyEditorRegistry} 屬性編輯器註冊表 * 4. {@link org.springframework.core.convert.ConversionService} 類型轉換器(Spring 3+,替換了以前的 TypeConverter) */ BeanWrapper instanceWrapper = null; // <1.1> 若是是單例模式,則先嚐試從 `factoryBeanInstanceCache` 緩存中獲取實例對象,並從緩存中移除 if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // <1.2> 使用合適的實例化策略來建立 Bean 的實例:工廠方法、構造函數自動注入、簡單初始化 // 主要是將 BeanDefinition 轉換爲 BeanWrapper 對象 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } // <1.3> 獲取包裝的實例對象 `bean` final Object bean = instanceWrapper.getWrappedInstance(); // <1.4> 獲取包裝的實例對象的類型 `beanType` Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; }
Bean 的實例化階段,會將 Bean 的實例對象封裝成 BeanWrapperImpl 包裝對象,BeanWrapperImpl 承擔的角色:緩存
若是是單例模式,則先嚐試從 factoryBeanInstanceCache
緩存(保存 FactoryBean 類型的對象)中獲取實例對象,並從緩存中移除。目前在建立 Bean 的過程當中沒發現往這個集合中添加緩存,暫時忽略。咱們直接看到下面的一步,調用 createBeanInstance(...)
方法來建立一個實例對象,咱們進去看看安全
createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法,建立一個 Bean 的實例對象,以下:app
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. // <1> 獲取 `beanName` 對應的 Class 對象 Class<?> beanClass = resolveBeanClass(mbd, beanName); 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()); } // <2> 若是存在 Supplier 實例化回調接口,則使用給定的回調方法建立一個實例對象 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // <3> 若是配置了 `factory-method` 工廠方法,則調用該方法來建立一個實例對象 // 經過 @Bean 標註的方法會經過這裏進行建立 if (mbd.getFactoryMethodName() != null) { // 這個過程很是複雜,你能夠理解爲: // 找到最匹配的 Method 工廠方法,獲取相關參數(依賴注入),而後經過調用該方法返回一個實例對象(反射機制) return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... // <4> 判斷這個 RootBeanDefinition 的構造方法是否已經被解析出來了 // 由於找到最匹配的構造方法比較繁瑣,找到後會設置到 RootBeanDefinition 中,避免重複這個過程 boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { // 加鎖 // <4.1> 構造方法已經解析出來了 if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; // <4.2> 這個構造方法有入參,表示須要先獲取到對應的入參(構造器注入) autowireNecessary = mbd.constructorArgumentsResolved; } } } // <5> 若是最匹配的構造方法已解析出來 if (resolved) { // <5.1> 若是這個構造方法有入參 if (autowireNecessary) { // 這個過程很複雜,你能夠理解爲: // 找到最匹配的構造方法,這裏會拿到已經被解析出來的這個方法,並找到入參(構造器注入),而後調用該方法返回一個實例對象(反射機制) return autowireConstructor(beanName, mbd, null, null); } // <5.2> 不然,沒有入參 else { // 直接調用解析出來構造方法,返回一個實例對象(反射機制) return instantiateBean(beanName, mbd); } } // Candidate constructors for autowiring? // <6> 若是最匹配的構造方法還沒開始解析,那麼須要找到一個最匹配的構造方法,而後建立一個實例對象 /** * <6.1> 嘗試經過 SmartInstantiationAwareBeanPostProcessor 處理器的 determineCandidateConstructors 方法來找到一些合適的構造方法 * 參考 {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors} */ Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // <6.2> 是否知足下面其中一個條件 if (ctors != null // 上一步找到了合適的構造方法 || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR // 構造器注入 || mbd.hasConstructorArgumentValues() // 定義了構造方法的入參 || !ObjectUtils.isEmpty(args)) // 當前方法指定了入參 { // 找到最匹配的構造方法,若是 `ctors` 不爲空,會從這裏面找一個最匹配的, // 並找到入參(構造器注入),而後調用該方法返回一個實例對象(反射機制) return autowireConstructor(beanName, mbd, ctors, args); } // Preferred constructors for default construction? /** * <7> 若是第 `6` 步還不知足,那麼嘗試獲取優先的構造方法 * 參考 {@link org.springframework.context.support.GenericApplicationContext.ClassDerivedBeanDefinition} */ ctors = mbd.getPreferredConstructors(); if (ctors != null) { // <7.1> 若是存在優先的構造方法,則從裏面找到最匹配的一個,並找到入參(構造器注入),而後調用該方法返回一個實例對象(反射機制) return autowireConstructor(beanName, mbd, ctors, null); } // No special handling: simply use no-arg constructor. // <8> 若是上面多種狀況都不知足,那隻能使用兜底方法了,直接調用默認構造方法返回一個實例對象(反射機制) return instantiateBean(beanName, mbd); }
過程大體以下:
獲取 beanName
對應的 Class 對象
若是存在 Supplier 實例化回調接口,則使用給定的回調方法建立一個實例對象,調用 obtainFromSupplier(...) 方法建立
若是配置了 factory-method
工廠方法,則調用該方法來建立一個實例對象,經過 @Bean 標註的方法會經過這裏進行建立,調用 instantiateUsingFactoryMethod(...) 方法建立
若是上面兩種狀況都不是,那麼就進行接下來正常建立 Bean 實例的一個過程
判斷這個 RootBeanDefinition 的構造方法是否已經被解析出來了,由於找到最匹配的構造方法比較繁瑣,找到後會設置到 RootBeanDefinition 中,避免重複這個過程
resolvedConstructorOrFactoryMethod
是否不爲空,不爲空表示構造方法已經解析出來了constructorArgumentsResolved
是否不爲空,不爲空表示有入參,須要先獲取到對應的入參(構造器注入)若是最匹配的構造方法已解析出來
若是最匹配的構造方法還沒開始解析,那麼須要找到一個最匹配的構造方法,而後建立一個實例對象
先嚐試經過 SmartInstantiationAwareBeanPostProcessor 處理器找到一些合適的構造方法,保存在 ctors
中
是否知足下面其中一個條件:ctors
不爲空、構造器注入模式、定義了構造方法的入參、當前方法指定了入參,
則找到最匹配的構造方法,若是 ctors
不爲空,會從這裏面找一個最匹配的,並找到入參(構造器注入),而後調用該方法返回一個實例對象(反射機制),調用 autowireConstructor(...) 方法建立
若是第 6
步還不知足,那麼嘗試從 RootBeanDefinition 中獲取優先的構造方法
若是上面多種狀況都不知足,那隻能使用兜底方法了,直接調用默認構造方法返回一個實例對象(反射機制),調用 instantiateBean(...) 方法建立
整個的實例化過程很是的複雜,主要分爲如下幾種狀況:
factory-method
工廠方法建立當前 Bean,則找到這個方法,而後建立一個實例對象(@Bean 註解底層原理也是這種方式)這四種狀況,其實就分別對應上面四個加粗的方法,接下來依次分析這四個方法
obtainFromSupplier(Supplier<?> instanceSupplier, String beanName)
方法,經過 Supplier 回調接口獲取一個實例對象,方法以下:
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) { Object instance; // 得到原當前線程正在建立的 Bean 的名稱 String outerBean = this.currentlyCreatedBean.get(); // 設置當前線程正在建立的 Bean 的名稱 this.currentlyCreatedBean.set(beanName); try { // <1> 調用 Supplier 的 get(),返回一個實例對象 instance = instanceSupplier.get(); } finally { if (outerBean != null) { // 設置原當前線程正在建立的 Bean 的名稱到當前線程變量中 this.currentlyCreatedBean.set(outerBean); } else { this.currentlyCreatedBean.remove(); } } // 未建立 Bean 對象,則建立 NullBean 空對象 if (instance == null) { instance = new NullBean(); } // <2> 將實例對象封裝成 BeanWrapper 對象 BeanWrapper bw = new BeanWrapperImpl(instance); // <3> 初始化這個 BeanWrapper 對象 initBeanWrapper(bw); return bw; }
過程以下:
get()
,返回 instance
實例對象instance
封裝成 BeanWrapper 對象 bw
bw
進行初始化,設置 ConversionService 類型轉換器,並註冊自定義的屬性編輯器整個過程比較簡單
經過 factoryMethodName
工廠方法建立一個實例對象,例如 XML 配置的 factory-method
屬性或者 @Bean
標註的方法都會解析成 factoryMethodName
屬性
這個過程很是複雜,你能夠理解爲去找到最匹配的 Method 工廠方法,獲取相關入參(依賴注入),而後調用該方法返回一個實例對象(反射機制),方法以下:
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs); }
建立 ConstructorResolver 對象,而後調用其 instantiateUsingFactoryMethod(...)
方法,以下:
// ConstructorResolver.java public BeanWrapper instantiateUsingFactoryMethod( String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 構造 BeanWrapperImpl 對象 BeanWrapperImpl bw = new BeanWrapperImpl(); // 初始化 BeanWrapperImpl,設置 ConversionService 類型轉換器,並註冊自定義的屬性編輯器 this.beanFactory.initBeanWrapper(bw); // -------------------------獲取工廠方法的相關信息------------------------- // <1> 獲取工廠方法的相關信息 // 工廠方法所在類對應的 Bean(靜態方法不會有) Object factoryBean; // 工廠方法所在類的 Class 對象 Class<?> factoryClass; // 是否爲 static 修飾的靜態方法 boolean isStatic; // 獲取工廠方法所在類對應的 Bean 的名稱(靜態方法不會有) String factoryBeanName = mbd.getFactoryBeanName(); // <1.1> 非靜態方法 if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } // 獲取工廠方法所在類對應的 Bean,否則沒法調用工廠方法 factoryBean = this.beanFactory.getBean(factoryBeanName); // 若是是單例模式,已經存在對應的 Bean,則拋出重複建立的異常 if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } factoryClass = factoryBean.getClass(); isStatic = false; } // <1.2> 靜態方法 else { // It's a static factory method on the bean class. // 靜態方法沒有找到對應的 Class 對象沒法被調用,則拋出異常 if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference"); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } // -------------------------嘗試獲取工廠方法對象和入參------------------------- // <2> 嘗試獲取工廠方法對象和參數 // 工廠方法對象 Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; // 方法參數 Object[] argsToUse = null; // <2.1> 若是方法入參指定了參數,則直接使用 if (explicitArgs != null) { argsToUse = explicitArgs; } // <2.2> 不然,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參 else { Object[] argsToResolve = null; // 由於可能前面解析了,會臨時緩存,避免再次解析 synchronized (mbd.constructorArgumentLock) { // 加鎖 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; // 若是工廠方法被解析了,那麼參數也可能解析過 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // Found a cached factory method... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { // 沒有解析過的參數,則嘗試從 RootBeanDefinition 中獲取未被解析過的參數 argsToResolve = mbd.preparedConstructorArguments; } } } // 若是獲取到了未被解析過的入參,則進行解析 if (argsToResolve != null) { // 處理參數值,類型轉換,例如給定方法 A(int, int),配置了 A("1"、"2") 兩個參數,則會轉換爲 A(1, 1) argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); } } // -------------------------找到全部匹配的工廠方法------------------------- // <3> 若是上一步沒有找到工廠方法對象或方法入參集合,則須要進行接下來的解析過程,首先找到全部匹配的工廠方法 if (factoryMethodToUse == null || argsToUse == null) { // Need to determine the factory method... // Try all methods with this name to see if they match the given arguments. // <3.1> 獲取工廠方法所在的類的實例 Class 對象,由於多是 Cglib 提高過的子類 factoryClass = ClassUtils.getUserClass(factoryClass); // <3.2> 獲取工廠方法所在的類中全部方法對象 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); // <3.3> 找到這個類中匹配的工廠方法 List<Method> candidateList = new ArrayList<>(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic // 是否和 `isStatic` 匹配 && mbd.isFactoryMethod(candidate)) { // 和定義的工廠方法的名稱是否相等 candidateList.add(candidate); } } // <3.4> 若是隻有一個匹配的方法,且這個方法沒有給指定的入參,且自己也沒有定義參數,且這個方法沒有定義入參 // 則直接調用這個方法建立一個實例對象(反射機制),並返回 if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Method uniqueCandidate = candidateList.get(0); if (uniqueCandidate.getParameterCount() == 0) { mbd.factoryMethodToIntrospect = uniqueCandidate; synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS)); return bw; } } // -------------------------開始找最匹配的工廠方法------------------------- // <4> 開始找最匹配的工廠方法 // 將匹配的工廠方法轉換成數組 Method[] candidates = candidateList.toArray(new Method[0]); // 將匹配的方法進行排序,public 方法優先,入參個數多的優先 AutowireUtils.sortFactoryMethods(candidates); // 用於承載解析後的方法參數值 ConstructorArgumentValues resolvedValues = null; // 是不是構造器注入 boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); int minTypeDiffWeight = Integer.MAX_VALUE; // 匹配方法的集合 Set<Method> ambiguousFactoryMethods = null; // -------------------------肯定方法參數的入參數量------------------------- // <5> 肯定方法參數的入參數量,匹配的方法的入參數量要多餘它 // 方法的參數數量的最小值 int minNrOfArgs; // <5.1> 若是當前方法指定了入參,則使用其個數做爲最小值 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } // <5.1> 不然,從 RootBeanDefinition 解析出方法的參數個數做爲最小值 else { // We don't have arguments passed in programmatically, so we need to resolve the // arguments specified in the constructor arguments held in the bean definition. // RootBeanDefinition 定義了參數值 if (mbd.hasConstructorArgumentValues()) { // 方法的參數 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); // 解析定義的參數值,放入 `resolvedValues` 中,並返回參數個數 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { minNrOfArgs = 0; } } // 記錄 UnsatisfiedDependencyException 異常的集合 LinkedList<UnsatisfiedDependencyException> causes = null; // 遍歷匹配的方法 for (Method candidate : candidates) { // 方法體的參數 Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { // -------------------------解析出工廠方法的入參------------------------- // <6> 解析出工廠方法的入參 // 保存參數的對象 ArgumentsHolder argsHolder; // <6.1> 若是當前方法指定了入參,則直接使用 if (explicitArgs != null) { // Explicit arguments given -> arguments length must match exactly. // 顯示給定參數,參數長度必須徹底匹配 if (paramTypes.length != explicitArgs.length) { continue; } // 根據參數建立參數持有者 ArgumentsHolder 對象 argsHolder = new ArgumentsHolder(explicitArgs); } // <6.2> 不然,經過**依賴注入**獲取入參 else { // Resolved constructor arguments: type conversion and/or autowiring necessary. // 爲提供參數,解析構造參數 try { String[] paramNames = null; // 獲取 ParameterNameDiscoverer 參數名稱探測器 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); // 獲取方法的參數名稱 if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } // 解析出方法的入參,參數值會被依賴注入 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { // 若發生 UnsatisfiedDependencyException 異常,添加到 causes 中。 if (logger.isTraceEnabled()) { logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } // -------------------------根據權重獲取最匹配的方法------------------------- // <7> 由於會遍歷全部匹配的方法,因此須要進行權重的判斷,拿到最優先的那個 // 判斷解析構造函數的時候是否以寬鬆模式仍是嚴格模式,默認爲 true // 嚴格模式:解析構造函數時,必須全部的都須要匹配,不然拋出異常 // 寬鬆模式:使用具備"最接近的模式"進行匹配 // typeDiffWeight:類型差別權重 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this factory method if it represents the closest match. // 表明最匹配的結果,則選擇做爲符合條件的方法 if (typeDiffWeight < minTypeDiffWeight) { factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } // Find out about ambiguity: In case of the same type difference weight // for methods with the same number of parameters, collect such candidates // and eventually raise an ambiguity exception. // However, only perform that check in non-lenient constructor resolution mode, // and explicitly ignore overridden methods (with the same parameter signature). // 若是具備相同參數數量的方法具備相同的類型差別權重,則收集此類型選項 // 可是,僅在非寬鬆構造函數解析模式下執行該檢查,並顯式忽略重寫方法(具備相同的參數簽名) else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterCount() && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) { // 查找到多個可匹配的方法 if (ambiguousFactoryMethods == null) { ambiguousFactoryMethods = new LinkedHashSet<>(); ambiguousFactoryMethods.add(factoryMethodToUse); } ambiguousFactoryMethods.add(candidate); } } } // <8> 沒有找到對應的工廠方法,則拋出異常 if (factoryMethodToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } List<String> argTypes = new ArrayList<>(minNrOfArgs); if (explicitArgs != null) { for (Object arg : explicitArgs) { argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null"); } } else if (resolvedValues != null) { Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount()); valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values()); valueHolders.addAll(resolvedValues.getGenericArgumentValues()); for (ValueHolder value : valueHolders) { String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) : (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null")); argTypes.add(argType); } } String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes); throw new BeanCreationException(mbd.getResourceDescription(), beanName, "No matching factory method found: " + (mbd.getFactoryBeanName() != null ? "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " + "Check that a method with the specified name " + (minNrOfArgs > 0 ? "and arguments " : "") + "exists and that it is " + (isStatic ? "static" : "non-static") + "."); } else if (void.class == factoryMethodToUse.getReturnType()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid factory method '" + mbd.getFactoryMethodName() + "': needs to have a non-void return type!"); } else if (ambiguousFactoryMethods != null) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Ambiguous factory method matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousFactoryMethods); } // <9> 將解析出來的工廠方法和入參緩存,設置到 RootBeanDefinition 中,由於整個過程比較複雜,避免再次解析 if (explicitArgs == null && argsHolderToUse != null) { mbd.factoryMethodToIntrospect = factoryMethodToUse; argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } Assert.state(argsToUse != null, "Unresolved factory method arguments"); // <10> 調用工廠方法建立一個實例對象(反射機制),並設置到 `bw` 中 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse)); return bw; }
這個方法我真的是吐了😢,也太長了吧,硬着頭皮看完了一部分,參考文件:ConstructorResolver.java
對於過程不感興趣的能夠跳過直接看下面的歸納,過程大體以下:
先建立一個 BeanWrapperImpl 對象 bw
,並初始化,設置 ConversionService 類型轉換器,並註冊自定義的屬性編輯器
factoryBeanName
屬性判斷是否爲靜態方法,這個屬性表示這個工廠方法所在類對應 Bean 的名稱,固然靜態方法「不屬於」這個 Bean,因此它的這個屬性爲空
factoryBeanName
屬性不爲空,表示不是靜態方法,則須要根據 factoryBeanName
找到(依賴查找)對應的 Bean,做爲 factoryBean
這一步找到了三個對象:factoryBean
(工廠方法所在類對應的 Bean,靜態方法不會有)、factoryClass
(工廠方法所在類的 Class 對象)、isStatic
(是否爲靜態方法)。因此想要經過工廠方法獲取一個 Bean,則須要方法所在類對應的 Bean 先初始化,而後才能調用這個方法建立 Bean;而靜態方法就不用,由於它能夠根據所在類的 Class 對象就能調用這個方法建立 Bean,這就是二者的區別。
嘗試獲取工廠方法 Method 對象和入參
若是方法入參指定了參數,則直接使用
不然,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參,若是獲取到了未被解析過的入參,則進行解析(類型轉換)
例如給定方法 A(int, int),配置了 A("1"、"2") 兩個參數,則會轉換爲 A(1, 1)
這一步嘗試獲取兩個對象:factoryMethodToUse
(對應的工廠方法 Method)、argsToUse
(工廠方法的入參集合)
isStatic
匹配,而且和定義的工廠方法的名稱是否相等上面第 3.3
步找到的一般只有一個,若是沒有入參則能夠直接進入第 3.4
步,使用這個方法建立一個實例對象。不過你可能定義了重載方法,也可能定義了方法參數,因此須要進行接下來的解析過程
這一步主要是肯定入參的個數,並排序全部匹配的方法,接下來會遍歷全部匹配的方法
這一步會找到這個方法的入參,依賴注入的方式
一般狀況下,咱們只有一個匹配的方法,若是存在多個,會根據方法的參數類型進行權重
會緩存這幾個數據:resolvedConstructorOrFactoryMethod
(已經解析出來的工廠方法)、constructorArgumentsResolved
(方法入參已經解析出來了 true)、resolvedConstructorArguments
(解析出來的入參)
bw
中上面整個過程很是複雜,這裏進行簡單歸納:
找到對應的工廠方法,若是是非靜態方法,則須要先依賴查找到所在類對應的 Bean,由於須要根據這個 Bean 去調用對應的工廠方法,而靜態方法不用,能夠根據其 Class 對象調用對應的工廠方法
若是工廠方法有入參,則須要注入相關對象(依賴注入)
調用這個方法(反射機制),返回一個實例對象
這個過程和上一個方法同樣很是複雜,不過差不太多,你能夠理解爲去找到當前 Bean 的構造方法,獲取相關入參(構造器注入),而後調用該構造方法返回一個實例對象(反射機制),方法以下:
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); }
建立 ConstructorResolver 對象,而後調用其 autowireConstructor(...)
方法,以下:
// ConstructorResolver.java public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { // 構造 BeanWrapperImpl 對象 BeanWrapperImpl bw = new BeanWrapperImpl(); // 初始化 BeanWrapperImpl,設置 ConversionService 類型轉換器,並註冊自定義的屬性編輯器 this.beanFactory.initBeanWrapper(bw); // -------------------------嘗試獲取構造方法和入參------------------------- // <1> 嘗試獲取構造方法和入參 // 構造方法 Constructor<?> constructorToUse = null; ArgumentsHolder argsHolderToUse = null; // 構造方法的入參集合 Object[] argsToUse = null; // <1.1> 若是當前方法入參指定了參數,則直接使用 if (explicitArgs != null) { argsToUse = explicitArgs; } // <1.2> 不然,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參 else { // 由於可能前面解析了,會臨時緩存,避免再次解析 Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; // 若是構造方法被解析了,那麼參數也可能解析過 if (constructorToUse != null && mbd.constructorArgumentsResolved) { // Found a cached constructor... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { // 沒有解析過的參數,則嘗試從 RootBeanDefinition(合併後)中獲取未被解析過的參數 argsToResolve = mbd.preparedConstructorArguments; } } } // 若是獲取到了未被解析過的入參 if (argsToResolve != null) { // 處理參數值,類型轉換,例如給定方法 A(int, int),配配置了 A("1"、"2") 兩個參數,則會轉換爲 A(1, 1) argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); } } // -------------------------開始獲取構造方法和入參------------------------- // <2> 若是上一步沒有找到構造方法或入參集合,找到全部匹配的工廠方法,首先找到全部匹配的構造方法 if (constructorToUse == null || argsToUse == null) { // Take specified constructors, if any. // <2.1> 獲取全部的構造方法,若是當前方法指定了構造方法的集合,則使用這個集合 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); } } // <2.2> 若是構造方法只有一個,且當前方法的入參沒有指定參數,且自己也沒有定義參數,且這個構造方法沒有定義入參 // 則直接調用這個構造方法建立一個實例對象(反射機制),並返回 if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Constructor<?> uniqueCandidate = candidates[0]; if (uniqueCandidate.getParameterCount() == 0) { synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS)); return bw; } } // Need to resolve the constructor. // 是不是構造器注入 boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); // 用於承載解析後的方法參數值 ConstructorArgumentValues resolvedValues = null; // -------------------------肯定構造方法的入參數量------------------------- // <3> 肯定構造參數的入參數量,匹配的方法的入參數量要多餘它 // 方法的參數數量的最小值 int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } // 從 RootBeanDefinition 解析出方法的參數個數做爲最小值 else { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } // <4> 將全部的構造方法進行排序,public 方法優先,入參個數多的優先 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 (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) { // Already found greedy constructor that can be satisfied -> // do not look any further, there are only less greedy constructors left. break; } // 若是這個構造方法的參數個數小於入參數量,則跳過 if (paramTypes.length < minNrOfArgs) { continue; } // -------------------------解析出構造方法的入參------------------------- // <5> 解析出構造方法的入參 // 保存參數的對象 ArgumentsHolder argsHolder; // <5.2> 經過**依賴注入**獲取入參 if (resolvedValues != null) { try { // 獲取構造方法的參數名稱(@ConstructorProperties 註解) String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); if (paramNames == null) { // 沒有獲取到則經過 ParameterNameDiscoverer 參數探測器獲取參數名稱 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } } // 解析出方法的入參,參數值會被依賴注入 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next constructor. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } // <5.1> 若是當前方法的入參指定了參數,若是個數相等則直接使用 else { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } // -------------------------根據權重獲取最匹配的方法------------------------- // <6> 由於會遍歷全部匹配的方法,因此須要進行權重的判斷,拿到最優先的那個 // 判斷解析構造函數的時候是否以寬鬆模式仍是嚴格模式,默認爲 true // 嚴格模式:解析構造函數時,必須全部的都須要匹配,不然拋出異常 // 寬鬆模式:使用具備"最接近的模式"進行匹配 // typeDiffWeight:類型差別權重 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this constructor if it represents the closest match. // 表明最匹配的結果,則選擇做爲符合條件的方法 if (typeDiffWeight < minTypeDiffWeight) { constructorToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousConstructors = null; } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) { if (ambiguousConstructors == null) { ambiguousConstructors = new LinkedHashSet<>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); } } // <7> 沒有找到對應的構造方法,則拋出異常 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)"); } 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); } // <8> 將解析出來的工廠方法和入參緩存,設置到 RootBeanDefinition 中,由於整個過程比較複雜,避免再次解析 if (explicitArgs == null && argsHolderToUse != null) { argsHolderToUse.storeCache(mbd, constructorToUse); } } Assert.state(argsToUse != null, "Unresolved constructor arguments"); // <9> 調用這個構造方法返回一個實例對象(反射機制),並設置到 `bw` 中 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); return bw; }
這個方法我也是吐了😢,不過還好,和上一個方法邏輯差很少,硬着頭皮,參考文件:ConstructorResolver.java
對於過程不感興趣的能夠跳過直接看下面的歸納,過程大體以下:
先建立一個 BeanWrapperImpl 對象 bw
,並初始化,設置 ConversionService 類型轉換器,並註冊自定義的屬性編輯器
嘗試獲取構造方法和入參
若是當前方法入參指定了參數,則直接使用
不然,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參,若是獲取到了未被解析過的入參,則進行解析(類型轉換)
例如給定方法 A(int, int),配置了 A("1"、"2") 兩個參數,則會轉換爲 A(1, 1)
這一步嘗試獲取兩個對象:constructorToUse
(構造方法)、argsToUse
(構造方法的入參集合)
若是上一步沒有找到構造方法或入參集合,找到全部匹配的工廠方法,首先找到全部匹配的構造方法
獲取全部的構造方法,若是當前方法指定了構造方法的集合,則使用這個集合
若是構造方法只有一個,且當前方法的入參沒有指定參數,且自己也沒有定義參數,且這個構造方法沒有定義入參
則直接調用這個構造方法建立一個實例對象(反射機制),並返回
上面第 2.2
步,一般只有默認構造方法纔會直接調用並返回的,不然須要進行接下來的解析過程
這一步主要是肯定入參的個數,並排序全部匹配的構造方法,接下來會遍歷全部匹配的構造方法
若是前面已經找到匹配的構造方法和入參,則直接結束循環;若是這個構造方法的參數個數小於入參數量,則跳過
這一步會找到這個構造方法的入參,構造器注入的方式
會緩存這幾個數據:resolvedConstructorOrFactoryMethod
(已經解析出來的構造方法)、constructorArgumentsResolved
(方法入參已經解析出來了 true)、resolvedConstructorArguments
(解析出來的入參)
bw
中上面整個過程很是複雜,這裏進行簡單歸納:
找到最匹配的構造方法
若是構造方法有入參,則須要注入相關對象(構造器注入,其實也是依賴注入獲取到的參數)
調用這個構造方法(反射機制),返回一個實例對象
兜底方法,若是構造方法找不到(或者已經解析出來的構造方法),則直接使用默認的構造方法(或者已經解析出來的構造方法),返回一個實例對象,方法以下:
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; // 安全模式 if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> // 得到 InstantiationStrategy 對象,並使用它,建立 Bean 對象 getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // 得到 InstantiationStrategy 對象,並使用它,建立 Bean 對象 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
能夠看到會經過 CglibSubclassingInstantiationStrategy#instantiate(...)
方法建立一個實例對象,該方法以下:
// SimpleInstantiationStrategy.java @Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. // <1> 沒有 MethodOverride 對象,也就是沒有須要覆蓋或替換的方法,則直接使用反射機制進行實例化便可 if (!bd.hasMethodOverrides()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { // <1.1> 嘗試從 RootBeanDefinition 得到已經解析出來的構造方法 `resolvedConstructorOrFactoryMethod` constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; // <1.2> 沒有解析出來的構造方法,則獲取默認的構造方法 if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); // 若是是接口,拋出 BeanInstantiationException 異常 if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { // 從 clazz 中,得到構造方法 if (System.getSecurityManager() != null) { // 安全模式 constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { constructorToUse = clazz.getDeclaredConstructor(); } // 標記 resolvedConstructorOrFactoryMethod 屬性 bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // <1.3> 經過這個構造方法實例化一個對象(反射機制) return BeanUtils.instantiateClass(constructorToUse); } // <2> 不然,經過 CGLIB 生成一個子類對象 else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } }
過程大體以下:
resolvedConstructorOrFactoryMethod
整個過程並不複雜
當咱們顯示或者隱式地調用AbstractBeanFactory
的 getBean(...)
方法時,會觸發 Bean 的加載,在《開啓 Bean 的加載》文章中分析了整個加載過程。
對於不一樣做用域的 Bean,底層都會調用 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程當中,須要先建立一個實例對象,這個過程在實例化階段完成,主要分爲下面幾種狀況:
factory-method
工廠方法建立當前 Bean,則找到這個方法,若是有入參,則須要找到對應的參數(依賴注入),而後建立一個實例對象(@Bean
註解底層原理也是這種方式)