❝你的贊是我最大的動力,期待與你共同進步web
❞
上一篇文章學習了在Spring中如何經過工廠方法來實例化對象的,詳細分析了createBeanInstance()
方法中調用的instantiateUsingFactoryMethod()
方法,今天這個片文章,未來分析另外一個被調用的方法 determineConstructorsFromBeanPostProcessors()
。方法入口以下: 在這個的實現中,咱們又看到了很是熟悉的 BeanPostProcessors
的處理,代碼以下:緩存
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException { if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName); if (ctors != null) { return ctors; } } } } return null; } 複製代碼
從上述代碼中,能夠看到 Spring 中的處理方式就是先獲取到全部的 BeanPostProcessors
的子類實現,而後循環判斷,若是有符合條件的, 那麼就調用該類的 determineCandidateConstructors()
方法,完成相應的處理。 在文章正式開始以前,又到了問問題的時候了, ibp.determineCandidateConstructors()
在執行 determineCandidateConstructors()
方法的 BeanPostProcessor
的實現類中,有一個 AutowiredAnnotationBeanPostProcessor
, 我這裏有一個問題,就是這個類是在何時放到 BeanDefinitionMap
中的呢?「請查看Spring容器初始化之先發五虎」。app
文章開始以前,仍是要從使用場景入手,而後在經過源碼來分析,畢竟源碼是不會騙人的。。。編輯器
@Service
public class DemoServiceOne { } 複製代碼
@Service
public class DemoServiceOne { @Autowired DemoServiceTwo demoServiceTwo; public DemoServiceOne(){} public DemoServiceOne(DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; } } 複製代碼
@Service
public class DemoServiceOne { @Autowired DemoServiceTwo demoServiceTwo; @Autowired DemoServiceThree demoServiceThree; public DemoServiceOne(DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; } public DemoServiceOne(DemoServiceThree demoServiceThree, DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; this.demoServiceThree = demoServiceThree; } } 複製代碼
@Service
public class DemoServiceOne { @Autowired DemoServiceTwo demoServiceTwo; @Autowired DemoServiceThree demoServiceThree; public DemoServiceOne(DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; } @Autowired public DemoServiceOne(DemoServiceThree demoServiceThree, DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; this.demoServiceThree = demoServiceThree; } } 複製代碼
從代碼的實現能夠看出,對於一個放在註冊到容器中的 BeanName
,都會作一次這個判斷。至於沒有交給Spring的類,這裏固然是不會作處理了。ide
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException { // Let's check for lookup methods here... // 首先檢查 lookup 方法 if (!this.lookupMethodsChecked.contains(beanName)) { try { ReflectionUtils.doWithMethods(beanClass, method -> { Lookup lookup = method.getAnnotation(Lookup.class); if (lookup != null) { Assert.state(this.beanFactory != null, "No BeanFactory available"); 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, "Cannot apply @Lookup to beans without corresponding bean definition"); } } }); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Lookup method resolution failed", ex); } this.lookupMethodsChecked.add(beanName); } // Quick check on the concurrent map first, with minimal locking. // 從緩存中查找 Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); // 緩存中沒有 if (candidateConstructors == null) { // 同步代碼塊 synchronized (this.candidateConstructorsCache) { candidateConstructors = this.candidateConstructorsCache.get(beanClass); if (candidateConstructors == null) { Constructor<?>[] rawCandidates; try { // 獲取 Bean的聲明的全部構造器, 無慘構造器也會被拿到 rawCandidates = beanClass.getDeclaredConstructors(); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Resolution of declared constructors on bean Class [" + beanClass.getName() + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } // 初始化候選的構造方法 list 大小爲 前面獲取到的類的構造參數個數 List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); //存放依賴注入的required=true的構造器 Constructor<?> requiredConstructor = null; //存放默認構造器 Constructor<?> defaultConstructor = null; //獲取主要的構造器,大多數的狀況下爲 null Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); int nonSyntheticConstructors = 0; for (Constructor<?> candidate : rawCandidates) { // 判斷構造器是否爲合成構造器,只要是咱們本身申明的都不是合成構造器 if (!candidate.isSynthetic()) { // 不是合成構造器,標記非合成構造器的數字 加一 nonSyntheticConstructors++; } else if (primaryConstructor != null) { continue; } //查找當前構造器上的註解,有些構造器上面可能有註解,有些沒有。這裏要作區分 AnnotationAttributes ann = findAutowiredAnnotation(candidate); if (ann == null) { // 沒有註解 // 獲取建立 Bean使用的 class Class<?> userClass = ClassUtils.getUserClass(beanClass); if (userClass != beanClass) { try { Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); ann = findAutowiredAnnotation(superCtor); } catch (NoSuchMethodException ex) { // Simply proceed, no equivalent superclass constructor found... } } } if (ann != null) { // 有註解 if (requiredConstructor != null) { //已經存在一個required=true的構造器了,拋出異常 throw new BeanCreationException(beanName, "Invalid autowire-marked constructor: " + candidate + ". Found constructor with 'required' Autowired annotation already: " + requiredConstructor); } //判斷此註解上的required屬性 默認爲 true 可設置爲 false // 這裏是用來處理兩個註解一個 required 爲 true,一個 爲false的狀況 boolean required = determineRequiredStatus(ann); if (required) { if (!candidates.isEmpty()) { throw new BeanCreationException(beanName, "Invalid autowire-marked constructors: " + candidates + ". Found constructor with 'required' Autowired annotation: " + candidate); } //若爲true //將當前構造器賦值給 requiredConstructor requiredConstructor = candidate; } // 當前的構造器添加到候選的構造器集合中 candidates.add(candidate); } //若是該構造函數上沒有註解,再判斷構造函數上的參數個數是否爲0 else if (candidate.getParameterCount() == 0) { //若是沒有參數,加入defaultConstructor集合,這裏能夠看出沒有構造器的狀況下,將無參構造器賦值給默認的構造器 defaultConstructor = candidate; } } //適用的構造器集合若不爲空 if (!candidates.isEmpty()) { // Add default constructor to list of optional constructors, as fallback. //若沒有required=true的構造器 if (requiredConstructor == null) { if (defaultConstructor != null) { //將defaultConstructor集合的構造器加入適用構造器集合 candidates.add(defaultConstructor); } else if (candidates.size() == 1 && logger.isInfoEnabled()) { logger.info("Inconsistent constructor declaration on bean with name '" + beanName + "': single autowire-marked constructor flagged as optional - " + "this constructor is effectively required since there is no " + "default constructor to fall back to: " + candidates.get(0)); } } //將適用構造器集合賦值給將要返回的構造器集合 candidateConstructors = candidates.toArray(new Constructor<?>[0]); } //若是適用的構造器集合爲空,且Bean只有一個構造器而且此構造器參數數量大於0 else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { //就使用此構造器來初始化 candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; } //若是構造器有兩個,且默認構造器不爲空 else if (nonSyntheticConstructors == 2 && primaryConstructor != null && defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) { //使用默認構造器返回 candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor}; } else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { candidateConstructors = new Constructor<?>[] {primaryConstructor}; } else { // 都不符合 初始化 candidateConstructors 若不初始化 後面的判斷會有問題 candidateConstructors = new Constructor<?>[0]; } //放入緩存,方便下一次調用,不須要上述的解析過程了,直接在緩存中獲取 this.candidateConstructorsCache.put(beanClass, candidateConstructors); } } } // 這裏能夠看到對 candidateConstructors 的初始化是有意義的 return (candidateConstructors.length > 0 ? candidateConstructors : null); } 複製代碼
首先來分析一下上述代碼主要住了什麼事,選取主要的步驟進行說明:函數
①:首先獲取類的構造方法,記錄在 Constructor<?>[] rawCandidates
中post
❝rawCandidates = beanClass.getDeclaredConstructors();無參構造器也會被拿到。下圖中,以類中沒有構造器的情形舉例學習
❞
②: for
循環 rawCandidates
對其中的每個構造器進行判斷flex
③:判斷構造器上是否加了註解ui
❝先判斷requiredConstructor集合是否爲空, 若不爲空則表明以前已經有一個required=true的構造器了,兩個true將拋出異常. 再判斷candidates 集合是否爲空,若不爲空則表示以前已經有一個打了註解的構造器,如有required又是true,拋出異常. 若上述判斷都經過了,將當前構造器賦值給 requiredConstructor集合中,再放入candidates集合中。
❞
❝若是是無慘構造器則賦值給 defaultConstructor,其餘的構造器不作處理,在會後返回的時候返回null
❞
④:沒有加註解且參數的個數爲 0。將當前 for
循環的構造方法賦值給 defaultConstructor
defaultConstructor = candidate;
複製代碼
⑤:肯定構造器 這裏肯定構造器仍是要結合前面的代碼去看。
構造器上沒有註解的狀況:
無參構造器將直接加入defaultConstructor集合中,不管是否申明。可是本方法最後返回的是 null
。最終的實例化是經過默認的構造函數來完成的 instantiateBean(beanName, mbd)
。
在構造器數量只有一個且有參數時,此惟一有參構造器將加入candidateConstructors集合中。最後返回。
在構造器數量大於1個,不管是否申明無參構造器的狀況下,將返回一個空的candidateConstructors集合,也就是沒有找到構造器。
❝不過這裏須要區分一下是否聲明無慘構造器: 若是未聲明 defaultConstructor 爲null 若是聲明瞭 defaultConstructor 不爲null
❞
綜上所述,在構造器沒有註解的狀況下,若是有且僅有一個非無慘的構造器,那麼本方法返回的就是這個構造器。若是大於一個或則只有一個 無參構造器,那麼該方法返回的都是 null
。
構造器上有註解的狀況須要判斷required屬性:
兩個構造器上都有 @Autowired
且 required屬性都爲true 拋出異常
❝throw new BeanCreationException(beanName, "Invalid autowire-marked constructor: " + candidate + ". Found constructor with 'required' Autowired annotation already: " + requiredConstructor);
❞
兩個構造器上都有 @Autowired
一個 required屬性都爲true 另外一個 required屬性都爲false 拋出異常
❝throw new BeanCreationException(beanName, "Invalid autowire-marked constructors: " + candidates + ". Found constructor with 'required' Autowired annotation: " + candidate);
❞
兩個構造器上都有 @Autowired
且 required屬性都爲false 則正常經過,後面的方法會肯定使用哪個
determineCandidateConstructors()
方法都會返回
null
。
「這裏有彩蛋,後面文章會提到」
對象中有且僅有一個未被注入的構造器
determineCandidateConstructors()
返回
null
determineCandidateConstructors()
返回 該構造器
true
拋出異常
true
另外一個爲
false
拋出異常
false
正常經過
這篇文章中對Spring中經過使用 BeanPostProcessor
的實現類來完成構造器的確認進行了分析。當咱們實例化一個對象的時候,構造方法肯定了, 那麼就能夠經過使用構造方法來實例化了。可是,經過上面的分析發現,可能會有多個構造方法存在的狀況,那麼在這種狀況下,Spring是如何肯定使用哪一個構造方法的, 也就是大名鼎鼎的推斷構造器,下一篇文章中,將進行分析。
本文使用 mdnice 排版