你知道Spring怎麼肯定實例化對象的構造器嗎?

你的贊是我最大的動力,期待與你共同進步web

1.開篇

  上一篇文章學習了在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

2 你真的知道Spring如何選擇構造器嗎?

  文章開始以前,仍是要從使用場景入手,而後在經過源碼來分析,畢竟源碼是不會騙人的。。。編輯器

2.1情形一
@Service
public class DemoServiceOne {  } 複製代碼
2.2情形二
@Service
public class DemoServiceOne {  @Autowired  DemoServiceTwo demoServiceTwo;   public DemoServiceOne(){}   public DemoServiceOne(DemoServiceTwo demoServiceTwo){  this.demoServiceTwo = demoServiceTwo;  } } 複製代碼
2.3情形三
@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;  } } 複製代碼
2.4情形四
@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;  } } 複製代碼

3 AutowiredAnnotationBeanPostProcessor 類中的方法

  從代碼的實現能夠看出,對於一個放在註冊到容器中的 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<?>[] rawCandidatespost

rawCandidates = beanClass.getDeclaredConstructors();無參構造器也會被拿到。下圖中,以類中沒有構造器的情形舉例學習

獲取類的構造器 ②: for 循環 rawCandidates 對其中的每個構造器進行判斷flex

③:判斷構造器上是否加了註解ui

  • 3.1 有加註解

    先判斷requiredConstructor集合是否爲空, 若不爲空則表明以前已經有一個required=true的構造器了,兩個true將拋出異常. 再判斷candidates 集合是否爲空,若不爲空則表示以前已經有一個打了註解的構造器,如有required又是true,拋出異常. 若上述判斷都經過了,將當前構造器賦值給 requiredConstructor集合中,再放入candidates集合中。

  • 3.2 沒有加註解

    若是是無慘構造器則賦值給 defaultConstructor,其餘的構造器不作處理,在會後返回的時候返回null

④:沒有加註解且參數的個數爲 0。將當前 for 循環的構造方法賦值給 defaultConstructor

defaultConstructor = candidate;
複製代碼

⑤:肯定構造器 肯定構造器   這裏肯定構造器仍是要結合前面的代碼去看。

4 情形分析

  • 構造器上沒有註解的狀況:

    • 無參構造器將直接加入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 則正常經過,後面的方法會肯定使用哪個

5 總結

    1. 對象中存在多個未被註解的構造器 determineCandidateConstructors()方法都會返回 null這裏有彩蛋,後面文章會提到
    1. 對象中有且僅有一個未被注入的構造器

      • 若該構造器爲無參的,那麼 determineCandidateConstructors()返回 null
      • 若該構造構器爲有參的,那麼 determineCandidateConstructors()返回 該構造器
    1. 僅有一個注入的構造器,則使用該構造器
    1. 有兩個注入的構造器
      • required 都爲 true 拋出異常
      • required 一個爲 true 另外一個爲 false 拋出異常
      • required 都爲 false 正常經過

  這篇文章中對Spring中經過使用 BeanPostProcessor 的實現類來完成構造器的確認進行了分析。當咱們實例化一個對象的時候,構造方法肯定了, 那麼就能夠經過使用構造方法來實例化了。可是,經過上面的分析發現,可能會有多個構造方法存在的狀況,那麼在這種狀況下,Spring是如何肯定使用哪一個構造方法的, 也就是大名鼎鼎的推斷構造器,下一篇文章中,將進行分析。

本文使用 mdnice 排版

相關文章
相關標籤/搜索