【1】前言
實體化這一步便是在doCreateBean方法的 instanceWrapper = createBeanInstance(beanName, mbd, args); 這段代碼中,
【2】對于實體化的疑問
對于Spring中的beanBeanDefinition,需要通過實體化得到一個bean物件才會被放入容器中,而實體化就需要用到構造方法,
分析:一個類存在多個構造方法,那么Spring進行實體化時,該如何去確定到呼叫哪個構造方法呢?
1. 如果開發者指定了想要使用的構造方法,那么就用這個構造方法,
2. 如果開發者沒有指定想要使用的構造方法,則看開發者有沒有讓Spring自動去選擇構造方法,
3. 如果開發者也沒有讓Spring自動去選擇構造方法,則Spring利用無參構造方法,如果沒有無參構造方法,則報錯,
開發者可以通過什么方式來指定使用哪個構造方法呢?
1.通過xml中的<constructor-arg>標簽,這個標簽表示構造方法引數,所以可以根據這個確定想要使用的構造方法的引數個數,從而確定想要使用的構造方法
2.通過@Autowired注解,@Autowired注解可以寫在構造方法上,所以哪個構造方法上寫了@Autowired注解,表示開發者想使用哪個構造方法,當然,它和第一個方式的不同點是,通過xml的方式,我們直接指定了構造方法的引數值,而通過@Autowired注解的方式,需要Spring通過byType+byName的方式去找到符合條件的bean作為構造方法的引數值,
3.如果Bean為注解@Lazy修飾的或者非單例的,可以通過getBean方法設定構造方法的入參,達到指定構造方法的效果,如,applicationContext.getBean("BeanDemo", new CircularRefA());【同理,獲取beanDefinition,使用beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());指定構造方法引數】
【3】推斷構造方法原始碼分析
1.主體代碼邏輯
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { /** * ----------0,校驗部分------------ */ 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()); } /** * ----------1,通過Supplier實體化部分------------ */ // BeanDefinition中添加了Supplier,則呼叫Supplier來得到物件 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } /** * ----------2,通過工廠方法實體化部分------------ */ // @Bean對應的BeanDefinition if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } /** * ----------3,用合適的建構式實體化部分------------ * * 一個類可能有多個構造器,所以Spring得根據引數個數、型別確定需要呼叫的構造器, * 原型的BeanDefinition,會多次來創建Bean,故在使用構造器創建實體后,Spring會將決議過后確定下來的構造器或工廠方法保存在快取中,避免再次創建相同bean時再次決議(節約時間) */ boolean resolved = false; //對構造器是否快取了 boolean autowireNecessary = false; //快取的構造器是否有引數 if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; // autowireNecessary表示有沒有必要要進行注入,比如當前BeanDefinition用的是無參構造方法,那么autowireNecessary為false,否則為true,表示需要給構造方法引數注入值 autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { // 如果確定了當前BeanDefinition的構造方法,那么看是否需要進行對構造方法進行引數的依賴注入(構造方法注入) if (autowireNecessary) { // 方法內會拿到快取好的構造方法的入參 return autowireConstructor(beanName, mbd, null, null); } else { // 構造方法已經找到了,但是沒有引數,那就表示是無參,直接進行實體化 return instantiateBean(beanName, mbd); } } //沒有快取,從bean后置處理器中為自動裝配尋找構造方法 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 找出最合適的默認構造方法 ctors = mbd.getPreferredConstructors(); if (ctors != null) { // 建構式自動注入 return autowireConstructor(beanName, mbd, ctors, null); } /** * ----------4,使用默認建構式構造部分------------ */ // 不匹配以上情況,則直接使用無參構造方法 return instantiateBean(beanName, mbd); }
代碼說明
createBeanInstance() 方法是 spring 實體化 bean 的核心代碼,它根據不同的情況會呼叫四種實體化方法:
1)obtainFromSupplier() :通過 Supplier 實體化
2)instantiateUsingFactoryMethod():通過工廠方法實體化
3)autowireConstructor():用合適的建構式實體化
4)instantiateBean():用無參建構式實體化
2.區域分析代碼
1)通過Supplier實體化部分決議
代碼
// BeanDefinition中添加了Supplier,則呼叫Supplier來得到物件 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); }
說明
Spring提供的一種機制,雖然不常用,通過設定實作Supplier介面的類,回傳一個另一種的物件,類似于FactoryBean的感覺,示例:
//在beanDefinition階段設定好 beanDefinition.setBeanClass(Student.class); beanDefinition.setInstanceSupplier(new Supplier<Object>() { @Override public Object get() { return new UserServiceImpl1(); } }); //容器啟動后嘗試獲取驗證 applicationContext.getBean("student"); //回傳new UserServiceImpl1()物件
2)通過工廠方法實體化部分針(同時也是@Bean注解的處理)決議【如果存疑可以查看 注解@Bean決議】
代碼塊
// @Bean對應的BeanDefinition if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); }
代碼深入部分:instantiateUsingFactoryMethod方法決議
protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { // 使用factoryBean來實體化物件 return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs); } //ConstructorResolver類#instantiateUsingFactoryMethod方法 //省略日志與例外 public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Object factoryBean; Class<?> factoryClass; boolean isStatic; //通過beanDefinition獲取到factoryBeanName ,實際就是@Bean注解的方法所在的configuration類 String factoryBeanName = mbd.getFactoryBeanName(); //表示非靜態方法 if (factoryBeanName != null) { if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(...); } factoryBean = this.beanFactory.getBean(factoryBeanName); // 該mbd已經創建過了【代表這個邏輯已經走過了】 if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } factoryClass = factoryBean.getClass(); isStatic = false; } else {//表示靜態方法 // It's a static factory method on the bean class. if (!mbd.hasBeanClass()) { throw new BeanDefinitionStoreException(...); } factoryBean = null; factoryClass = mbd.getBeanClass(); isStatic = true; } Method factoryMethodToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; //如果在呼叫getBean方法時有傳參,那就用傳的參作為@Bean注解的方法(工廠方法)的引數, 一般懶加載的bean才會傳參,啟動程序就實體化的實際上都沒有傳參 if (explicitArgs != null) { argsToUse = explicitArgs; } else { Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; //不為空表示已經使用過工廠方法,現在是再次使用工廠方法, 一般原型模式和Scope模式采用的上,直接使用該工廠方法和快取的引數 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // Found a cached factory method... argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); } } // 呼叫getBean方法沒有傳參,同時也是第一次使用工廠方法 if (factoryMethodToUse == null || argsToUse == null) { factoryClass = ClassUtils.getUserClass(factoryClass); // 獲取configuration類的所有候選方法 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); List<Method> candidateList = new ArrayList<>(); for (Method candidate : rawCandidates) { // 查找到與工廠方法同名的候選方法,即有@Bean的同名方法 if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { candidateList.add(candidate); } } //當與工廠方法同名的候選方法只有一個,且呼叫getBean方法時沒有傳參,且沒有快取過引數,直接通過呼叫實體化方法執行該候選方法 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; } } 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; int minNrOfArgs; // 如果呼叫getBean方法時有傳參,那么工廠方法最少引數個數要等于傳參個數 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { //如果getBean的時候沒有傳參,如果BeanDefinition中有設定,則從BeanDefinition中獲取 if (mbd.hasConstructorArgumentValues()) { ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); resolvedValues = new ConstructorArgumentValues(); minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { minNrOfArgs = 0; } } LinkedList<UnsatisfiedDependencyException> causes = null; for (Method candidate : candidates) { Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { ArgumentsHolder argsHolder; if (explicitArgs != null) { // Explicit arguments given -> arguments length must match exactly. if (paramTypes.length != explicitArgs.length) { continue; } argsHolder = new ArgumentsHolder(explicitArgs); } else { // Resolved constructor arguments: type conversion and/or autowiring necessary. try { String[] paramNames = null; ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } //當傳入的引數為空,需要根據工廠方法的引數型別注入相應的bean argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { 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; } } //計算工廠方法的權重 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // Choose this factory method if it represents the closest match. if (typeDiffWeight < minTypeDiffWeight) { /* * 當權重小時,重新設定factoryMethodToUse 和argsHolderToUse ,argsToUse , * 并把當前權重值設定為最小權重值,等待遍歷的下一個候選工廠方法比對, * 并且將ambiguousFactoryMethods (表示有含糊同樣權重的候選方法)設定為空 * */ factoryMethodToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousFactoryMethods = null; } /* * 當遍歷到下一個候選方法的時候,已經設定了factoryMethodToUse 且權重值與上一次的最小權重值相等時, * ambiguousFactoryMethods填值,這個ambiguousFactoryMethods不為空表示有兩個候選方法的最小權重相等, * spring無法匹配出最適合的工廠方法,如果再繼續往下遍歷候選器,有更小的權重值, * 那ambiguousFactoryMethods會再次被設定為空 * */ 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); } } } 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(...); } //回傳型別不能為void else if (void.class == factoryMethodToUse.getReturnType()) { throw new BeanCreationException(...); } //存在含糊的兩個工廠方法,不知選哪個 else if (ambiguousFactoryMethods != null) { throw new BeanCreationException(...); } if (explicitArgs == null && argsHolderToUse != null) { mbd.factoryMethodToIntrospect = factoryMethodToUse; argsHolderToUse.storeCache(mbd, factoryMethodToUse); } } //去實體化 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse)); return bw; }
3)用合適的建構式實體化部分決議
boolean resolved = false; //對構造器是否快取了 boolean autowireNecessary = false; //快取的構造器是否有引數 //判斷是否有傳參,因為getBean方法可以通過傳參指定構造方法引數型別來進行匹配(故這種對于引數的不確定是不能快取的) if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; // autowireNecessary表示有沒有必要要進行注入,比如當前BeanDefinition用的是無參構造方法,那么autowireNecessary為false,否則為true,表示需要給構造方法引數注入值 autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { // 如果確定了當前BeanDefinition的構造方法,那么看是否需要進行對構造方法進行引數的依賴注入(構造方法注入) if (autowireNecessary) { // 方法內會拿到快取好的構造方法的入參 return autowireConstructor(beanName, mbd, null, null); } else { // 構造方法已經找到了,但是沒有引數,那就表示是無參,直接進行實體化 return instantiateBean(beanName, mbd); } } //沒有快取,從bean后置處理器中為自動裝配尋找構造方法 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//存在推斷出來的構造方法集合 //BeanDefinition被設定為AUTOWIRE_CONSTRUCTOR //BeanDefinition指定了構造方法引數值 //getBean的時候傳入了構造方法引數值 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 找出最合適的默認構造方法 ctors = mbd.getPreferredConstructors(); if (ctors != null) { // 建構式自動注入 return autowireConstructor(beanName, mbd, ctors, null); }
代碼說明
【1】針對determineConstructorsFromBeanPostProcessors方法分析
代碼展示
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException { //如果類不為null,且存在InstantiationAwareBeanPostProcessor介面的處理器【其實用的不是它,而是他的子介面SmartInstantiationAwareBeanPostProcessor】 if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; //真正存在實作的類是AutowiredAnnotationBeanPostProcessor類 Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName); if (ctors != null) { return ctors; } } } } return null; } //AutowiredAnnotationBeanPostProcessor類#determineCandidateConstructors方法 //日志和例外的輸出會被省略 public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException { // 判斷是否檢測過 if (!this.lookupMethodsChecked.contains(beanName)) { try { // 遍歷目標類中的method,查看是否寫了@Lookup方法 ReflectionUtils.doWithMethods(beanClass, method -> { Lookup lookup = method.getAnnotation(Lookup.class); if (lookup != null) { Assert.state(this.beanFactory != null, "No BeanFactory available"); // 將當前method封裝成LookupOverride并設定到BeanDefinition的methodOverrides中 LookupOverride override = new LookupOverride(method, lookup.value()); try { RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName); mbd.getMethodOverrides().addOverride(override); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(beanName,"..."); } } }); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "...", ex); } this.lookupMethodsChecked.add(beanName); } //先從快取中獲取,看之前有沒有找過 Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); //快取中沒有 if (candidateConstructors == null) { // 加鎖,開始尋找 synchronized (this.candidateConstructorsCache) { //再次從快取中獲取,看被阻塞的時候沒有有執行緒已經找好了存在快取中(加鎖并雙重判斷的常規做法) candidateConstructors = this.candidateConstructorsCache.get(beanClass); if (candidateConstructors == null) { Constructor<?>[] rawCandidates; try { // 拿到所有的構造方法 rawCandidates = beanClass.getDeclaredConstructors(); } catch (Throwable ex) { throw new BeanCreationException(beanName, "...", ex); } List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); // 用來記錄required為true的構造方法,一個類中只能有一個required為true的構造方法 Constructor<?> requiredConstructor = null; // 用來記錄默認無參的構造方法 Constructor<?> defaultConstructor = null; // kotlin相關,不用管 Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); int nonSyntheticConstructors = 0; // 遍歷每個構造方法 for (Constructor<?> candidate : rawCandidates) { if (!candidate.isSynthetic()) { // 記錄一下普通的構造方法 nonSyntheticConstructors++; } else if (primaryConstructor != null) { continue; } // 當前遍歷的構造方法是否寫了@Autowired AnnotationAttributes ann = findAutowiredAnnotation(candidate); //沒有@Autowired注解的情況 if (ann == null) { // 如果beanClass是代理類,則得到被代理的類的型別 Class<?> userClass = ClassUtils.getUserClass(beanClass); if (userClass != beanClass) { try { //尋找被代理的類上的構造方法有沒有@Autowired注解 Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); ann = findAutowiredAnnotation(superCtor); } catch (NoSuchMethodException ex) {} } } /** * 構造方法如果有@Autowired注解,最后的操作是candidates.add(candidate),但如果出現兩種情況會拋出例外 * a、如果之前有遍歷過@Autowired的構造器,即requiredConstructor不為空 * b、如果當前的@Autowired的required屬性為true,不管之前遍歷過的@Autowired屬性是true還是false */ if (ann != null) { // 整個類中如果有一個required為true的構造方法,那就不能有其他的加了@Autowired的構造方法 if (requiredConstructor != null) { throw new BeanCreationException(...); } //獲取該方法上的@Autowired注解的required屬性 boolean required = determineRequiredStatus(ann); if (required) { if (!candidates.isEmpty()) { throw new BeanCreationException(...); } requiredConstructor = candidate; } // 記錄所有加了@Autowired的構造方法,不管required是true還是false,如果默認無參的構造方法上也加了@Autowired,那么也會加到candidates中 candidates.add(candidate); } else if (candidate.getParameterCount() == 0) { //沒有注解且引數個數為0【即無參】 // 記錄唯一一個無參的構造方法 defaultConstructor = candidate; } //但是這里沒有處理:有可能存在有參、并且沒有添加@Autowired的構造方法, } //存盤有@Autowired注解的構造方法的集合不為空 if (!candidates.isEmpty()) { // 如果不存在一個required為true的構造方法,則所有required為false的構造方法和無參構造方法都是合格的 if (requiredConstructor == null) { if (defaultConstructor != null) { //無參構造方法也添加到集合中 candidates.add(defaultConstructor); } else if (candidates.size() == 1 && logger.isInfoEnabled()) { logger.info(...); } } // 轉為陣列 candidateConstructors = candidates.toArray(new Constructor<?>[0]); } // 沒有添加了@Autowired注解的構造方法,并且類中只有一個構造方法,并且是有參的 else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; } // primaryConstructor不用管 else if (nonSyntheticConstructors == 2 && primaryConstructor != null && defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor}; } // primaryConstructor不用管 else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { candidateConstructors = new Constructor<?>[] {primaryConstructor}; } else { // 如果有多個有參、并且沒有添加@Autowired的構造方法,是會回傳空的 candidateConstructors = new Constructor<?>[0]; } //將結果存入快取 this.candidateConstructorsCache.put(beanClass, candidateConstructors); } } } //有候選構造器則回傳,沒有回傳null return (candidateConstructors.length > 0 ? candidateConstructors : null); } 回傳結果預測: 沒有加了@Autowired注解的構造方法 有多個構造方法 --》 回傳null 只有一個有參的構造方法 --》 回傳此構造方法 只有一個無參的構造方法 --》 回傳null 存在加了@Autowired注解的構造方法 只有一個required為true的構造方法 --》 回傳此構造方法 有多個required為true的構造方法 --》 拋例外 有一個required為true和其他的required為false的構造方法 --》 視情況而定,可能會拋例外,可能會回傳帶注解的構造方法 沒有required為true的構造方法 --》 回傳所有required為false的構造方法以及無參構造方法
發現說明
1.在多個構造方法上添加@Autowired注解會發生什么?
(1)因為@Autowired注解的required屬性默認為true,而根據原始碼展示,如果有一個構造方法上的@Autowired注解的required為true,那么后面的其他的構造方法不管@Autowired注解的required屬性是什么都會報錯,
(2)故如果要在多個構造方法上添加@Autowired注解,那么必須將他們的required屬性設定為false,(這種更安全)
(3)要么就是將@Autowired注解的required屬性設定為true的構造方法放到最后【僅限一個】
4)autowireConstructor方法分析
代碼展示
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); } public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) { this.beanFactory = beanFactory; this.logger = beanFactory.getLogger(); } //ConstructorResolver類#autowireConstructor方法 //省略一些例外和日志 public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { // 實體化BeanWrapper,是包裝bean的容器 BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Constructor<?> constructorToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; // 如果getBean()傳入了args,那構造方法要用的入參就直接確定好了 if (explicitArgs != null) { argsToUse = explicitArgs; } else { // 如果getBean()沒有傳入了引數 Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { // 嘗試從快取中獲取構造方法 constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; if (constructorToUse != null && mbd.constructorArgumentsResolved) { // 從快取中找到了構造器,那么繼續從快取中尋找快取的構造器引數 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { // 快取沒有的話,那就獲取BeanDefinition指定的那些引數【可以沒有指定】 argsToResolve = mbd.preparedConstructorArguments; } } } //argsToResolve不為空,即之前獲取到了引數【是從BeanDefinition指定的】要決議配置的引數 if (argsToResolve != null) { // 決議引數型別,比如將配置的String型別轉換為list、boolean等型別 argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); } } // 如果沒有確定要使用的構造方法,或者確定了構造方法但是所要傳入的引數值沒有確定 if (constructorToUse == null || argsToUse == null) { // 拿到傳入的構造器陣列 Constructor<?>[] candidates = chosenCtors; //陣列為空 if (candidates == null) { Class<?> beanClass = mbd.getBeanClass(); try { //使用public的構造器(默認)或者所有構造器 candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } catch (Throwable ex) { throw new BeanCreationException(...); } } // 如果只有一個候選構造方法,并且沒有指定所要使用的構造方法引數值,并且該構造方法是無參的,那就直接用這個無參構造方法進行實體化了 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; } } //需要決議建構式標志(當構造方法陣列不為空,或是自動裝配建構式時) boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); ConstructorArgumentValues resolvedValues = null; // 確定要選擇的構造方法的引數個數的最小值,后續判斷候選構造方法的引數個數如果小于minNrOfArgs,則直接pass掉 int minNrOfArgs; if (explicitArgs != null) { //如果直接傳了構造方法引數值,那么所用的構造方法的引數個數肯定不能少于 minNrOfArgs = explicitArgs.length; } else { // 提取BeanDefinition中的配置的建構式引數 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); // 用于承載決議后的建構式引數的值 resolvedValues = new ConstructorArgumentValues(); // 能決議到的引數個數 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } // 排序給定的建構式,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) { break; } if (paramTypes.length < minNrOfArgs) { // 引數個數不相等 continue; } ArgumentsHolder argsHolder; // 沒有通過getBean()指定構造方法引數值 if (resolvedValues != null) { try { // 有引數則根據值構造對應引數型別的引數 String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); if (paramNames == null) { // 獲取引數名稱探索器 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 (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } else { // 在調getBean方法是傳入了引數值,那就表示只能用對應引數個數的構造方法 if (paramTypes.length != explicitArgs.length) { continue; } // 建構式沒有引數的情況 argsHolder = new ArgumentsHolder(explicitArgs); } // 當前遍歷的構造方法所需要的入參物件都找到了,根據引數型別和找到的引數物件計算出來一個匹配值,值越小越匹配(Lenient表示寬松模式) int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // 值越小越匹配 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); } } // 遍歷結束 // 如果沒有可用的構造方法,就取記錄的最后一個例外并拋出 if (constructorToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } throw new BeanCreationException(...); } // 如果有可用的構造方法,但是有多個 else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) { throw new BeanCreationException(...); } if (explicitArgs == null && argsHolderToUse != null) { // 將決議的建構式加入快取 argsHolderToUse.storeCache(mbd, constructorToUse); } } // 將構造的實體加入BeanWrapper中 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); return bw; }
發現說明
1.autowireConstructor()大體流程
(1)先檢查是否指定了具體的構造方法和構造方法引數值,或者在BeanDefinition中快取了具體的構造方法或構造方法引數值,如果存在那么則直接使用該構造方法進行實體化
(2)如果沒有確定的構造方法或構造方法引數值,那么
1)如果沒有確定的構造方法,那么則找出類中所有的構造方法
2)如果只有一個無參的構造方法,那么直接使用無參的構造方法進行實體化
3)如果有多個可用的構造方法或者當前Bean需要自動通過構造方法注入
4)根據所指定的構造方法引數值,確定所需要的最少的構造方法引數值的個數
5)對所有的構造方法進行排序,引數個數多的在前面
6)遍歷每個構造方法
7)如果不是呼叫getBean方法時所指定的構造方法引數值,那么則根據構造方法引數型別找值
8) 如果時呼叫getBean方法時所指定的構造方法引數值,就直接利用這些值
9)如果根據當前構造方法找到了對應的構造方法引數值,那么這個構造方法就是可用的,但是不一定這個構造方法就是最佳的,所以這里會涉及到是否有多個構造方法匹配了同樣的值,這個時候就會用值和構造方法型別進行匹配程度的打分,找到一個最匹配的
2.為什么分越少優先級越高?
(1)主要是計算找到的bean和構造方法引數型別匹配程度有多高,
(2)示例:假設bean的型別為A,A的父類是B,B的父類是C,同時A實作了介面D 如果構造方法的引數型別為A,那么完全匹配,得分為0 如果構造方法的引數型別為B,那么得分為2 如果構造方法的引數型別為C,那么得分為4 如果構造方法的引數型別為D,那么得分為
Object[] objects = new Object[]{new A()}; // 0 System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects)); // 2 System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects)); // 4 System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects)); // 1 System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));
(3)所以,我們可以發現,越匹配分數越低
5)無參構造方法instantiateBean方法分析
//AbstractAutowireCapableBeanFactory類#instantiateBean方法 protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { try { Object beanInstance; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged( (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), getAccessControlContext()); } else { //獲取實體化策略并且進行實體化操作 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); } // 包裝成BeanWrapper BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } } //SimpleInstantiationStrategy類#instantiate方法 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // bd物件定義中,是否包含MethodOverride串列,spring中有兩個標簽引數會產生MethodOverrides,分別是lookup-method,replaced-method // 沒有MethodOverrides物件,可以直接實體化 if (!bd.hasMethodOverrides()) { // 實體化物件的構造方法 Constructor<?> constructorToUse; // 鎖定物件,使獲得實體化構造方法執行緒安全 synchronized (bd.constructorArgumentLock) { // 查看bd物件里使用否含有構造方法 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; // 如果沒有 if (constructorToUse == null) { // 從bd中獲取beanClass final Class<?> clazz = bd.getBeanClass(); // 如果要實體化的beanDefinition是一個介面,則直接拋出例外 if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { // 獲取系統安全管理器 if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { // 獲取默認的無參構造器 constructorToUse = clazz.getDeclaredConstructor(); } // 獲取到構造器之后將構造器賦值給bd中的屬性 bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // 通過反射生成具體的實體化物件 return BeanUtils.instantiateClass(constructorToUse); } else { // 必須生成cglib子類 return instantiateWithMethodInjection(bd, beanName, owner); } } public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.DECLARED); } private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException { //獲取所有的構造器 Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); //遍歷構造器,匹配的回傳 for (Constructor<T> constructor : constructors) { if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) { return getReflectionFactory().copyConstructor(constructor); } } throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes)); }
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/509788.html
標籤:其他
