分析一波Spring中factory-method如何實例化對象的?

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

1.回顧

  文章開篇,不得不前情提要走一波了。還記得 @Configuration 類中的@Bean方法是如何處理的嗎?@Bean方法中的對象是如何實例化的?小小的腦殼上面是否有大大的問號呢? 這裏作一個簡要回顧,首先看 @Bean 方法的處理: @Bean方法處理   而後在經過下面以系列的方法對其解析: @Bean方法解析概要緩存

  上述圖片中的最後一步,是否是很親切?是否是看到了熟悉的 registerBeanDefinition()方法?是否是還能想起 this.beanDefinitionMap.put(beanName , beanDefinition);app

  最後轉化成相應的 BeanDefinition 註冊到 BeanDefinitionMap 中去: @Bean之對象註冊編輯器

  首先咱們其中一個 BeanDefinition 爲例,從上圖中查看這個 BeanDefinition 中都包含哪些信息。 @Bean註解註冊的BDide

  這裏看到,將 BeanDefinition 註冊到 Map 中去了,可是這裏這個註冊並非這麼簡單的。這裏要對一下幾種狀況加以區分,要否則看到後面的 instantiateUsingFactoryMethod() 方法確定會懵圈的。下面咱們緊接着來分析分析 @Bean的處理情形...函數

  驗證幾種情形的須要的類:flex

public class DemoServiceOne {
 @Autowired  DemoServiceTwo demoServiceTwo;  public DemoServiceOne(){   }   public DemoServiceOne(DemoServiceTwo demoServiceTwo){  this.demoServiceTwo = demoServiceTwo;  } } 複製代碼
@Service
public class DemoServiceTwo { } 複製代碼
public class BeanDemoOne {
} 複製代碼
public class FactoryBeanDemoOne implements FactoryBean<BeanDemoOne> {
 @Override  public BeanDemoOne getObject() throws Exception {  return new BeanDemoOne();  }   @Override  public Class<?> getObjectType() {  return null;  }   @Override  public boolean isSingleton() {  return false;  }  public FactoryBeanDemoOne (){}   public FactoryBeanDemoOne (int i){   } } 複製代碼

1.1 靜態的 @Bean 方法

@Configuration
@ComponentScan("com.demo") public class DemoConfigOne {   @Bean("demoService")  public static DemoServiceOne demoServiceOne(){  return new DemoServiceOne();  } } 複製代碼
situation_01
situation_01

1.2 非靜態的構造方法

@Configuration
@ComponentScan("com.demo") public class DemoConfigOne {   @Bean  public FactoryBeanDemoOne demoFactoryBean() {  return new FactoryBeanDemoOne();  } } 複製代碼
situation_02
situation_02

1.3 經過兩個 @Bean 返回同類型的對象

@Configuration
@ComponentScan("com.demo") public class DemoConfigOne {   @Bean  public FactoryBeanDemoOne demoFactoryBean() {  return new FactoryBeanDemoOne();  }   @Bean  public FactoryBeanDemoOne demoFactoryBean() {  return new FactoryBeanDemoOne();  }  } 複製代碼
situation_03
situation_03

1.4 經過兩個 @Bean 返回指定名稱的同類型對象

@Configuration
@ComponentScan("com.demo") public class DemoConfigOne {   @Bean("demoOne")  public DemoServiceOne demoServiceOne(DemoServiceTwo demoServiceTwo){  return new DemoServiceOne(demoServiceTwo);  }   @Bean("demoTwo")  public DemoServiceOne demoServiceOne(){  return new DemoServiceOne();  }  } 複製代碼
situation_04
situation_04

2.經過工廠方法建立實例

  在不由感慨Spring的強大的同時,在看到某些方法的時候,也以爲某些方法好像不是那麼符合Spring的設計?下面這個方法,就是寫的比較繞的方法, 沒有辦法,只能硬着頭皮往下看。。。ui

public BeanWrapper instantiateUsingFactoryMethod(  String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {   // 構造 BeanWrapperImpl 對象  BeanWrapperImpl bw = new BeanWrapperImpl();  /*  * 初始化 BeanWrapperImpl  * 向BeanWrapper對象中添加 ConversionService 對象和屬性編輯器 PropertyEditor 對象  */  this.beanFactory.initBeanWrapper(bw);   Object factoryBean;  Class<?> factoryClass;  boolean isStatic;   // 經過beanDefinition獲取到factoryBeanName ,實際就是@Bean註解的方法 所在的 configuration類  String factoryBeanName = mbd.getFactoryBeanName();  if (factoryBeanName != null) {  // factoryBeanName 與 當前的 beanName 相同 拋出異常  if (factoryBeanName.equals(beanName)) {  throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,  "factory-bean reference points back to the same bean definition");  }  // 根據 BeanName 獲取 對象,就是 @Configuration 註解的類 這裏獲取到的是被 CGLIB 代理的類  factoryBean = this.beanFactory.getBean(factoryBeanName);  if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {  throw new ImplicitlyAppearedSingletonException();  }  // 獲取工廠類  factoryClass = factoryBean.getClass();  isStatic = false;  }  else {  // 工廠名稱爲空,則多是一個靜態工廠  // 若是有static 且爲工廠方法,則添加到 candidateList 中  // 這加這個判斷是以防漏掉 加了 static 的 @Bean 方法。固然,沒有加 @Bean 的方法就不會被考慮了  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;  }   // 工廠方法  Method factoryMethodToUse = null;  // 持有的參數  ArgumentsHolder argsHolderToUse = null;  // 使用的參數  Object[] argsToUse = null;   /*  * 工廠方法的參數,若是指定了構造參數,則直接使用  * @Bean註解的方法(工廠方法)的參數,在啓動過程當中實例化的對象 這裏通常都爲null,即通常不指定參數  * 追溯來源:就是 getBean() 方法中的 args 爲null  */  if (explicitArgs != null) {  argsToUse = explicitArgs;  }  else {  // 沒有指定  Object[] argsToResolve = null;  synchronized (mbd.constructorArgumentLock) {  // 首先嚐試從緩存中獲取  factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;  // 獲取緩存中的構造函數或者工廠方法,不爲空表示已經使用過工廠方法,那麼這裏會再次使用  // 通常原型模式和Scope模式採用的上,直接使用該工廠方法和緩存的參數  if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {  // 獲取緩存中的構造參數  argsToUse = mbd.resolvedConstructorArguments;  if (argsToUse == null) {  argsToResolve = mbd.preparedConstructorArguments;  }  }  }  // 緩存中存在,則解析存儲在 BeanDefinition 中的參數  // 如給定方法的構造函數 A(int ,int ),則經過此方法後就會把配置文件中的("1","1")轉換爲 (1,1)  // 緩存中的值多是原始值也有多是最終值  if (argsToResolve != null) {  argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);  }  }   // getBean() 方法沒有傳參數 或 沒有使用過 工廠方法  if (factoryMethodToUse == null || argsToUse == null) {  // 獲取工廠方法的類全名稱  factoryClass = ClassUtils.getUserClass(factoryClass);   // 獲取全部聲明的構造方法,默認容許訪問非公開的方法  Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);  // 檢索全部方法,這裏是對方法進行過濾  List<Method> candidateList = new ArrayList<>();  for (Method candidate : rawCandidates) {  if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {  // 添加到候選類裏面去  candidateList.add(candidate);  }  }   /**  * candidateList.size() == 1 表示待定的方法只有一個  * explicitArgs == null 調用getBean方法時沒有傳參  * !mbd.hasConstructorArgumentValues() 沒有緩存過參數,  * 直接經過調用實例化方法執行該候選方法  */  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 構造函數優先參數數量降序,非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 構造函數中指定的參數  if (mbd.hasConstructorArgumentValues()) {  // 構造函數的參數  ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();  // 解析構造函數的參數  // 將該 bean 的構造函數參數解析爲 resolvedValues 對象,其中會涉及到其餘 bean  resolvedValues = new ConstructorArgumentValues();  // 解析構造函數的參數 返回對應的參數個數 賦值給最小參數個數變量  minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);  }  else {  minNrOfArgs = 0;  }  }   LinkedList<UnsatisfiedDependencyException> causes = null;   // 遍歷候選方法 (這裏拿到的其實就是實例化 Bean 的構造方法)  for (Method candidate : candidates) {  // 方法的參數列表  Class<?>[] paramTypes = candidate.getParameterTypes();   if (paramTypes.length >= minNrOfArgs) {  // 保存參數的對象  ArgumentsHolder argsHolder;   // getBean()傳遞了參數  if (explicitArgs != null) {  // 顯示給定參數,參數長度必須徹底匹配  if (paramTypes.length != explicitArgs.length) {  continue;  }  // 根據參數建立參數持有者  argsHolder = new ArgumentsHolder(explicitArgs);  }  else {  // 未提供參數,解析構造參數  try {  String[] paramNames = null;  // 獲取 ParameterNameDiscoverer 對象  // 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) {  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;  }  }   // isLenientConstructorResolution 判斷解析構造函數的時候是否以寬鬆模式仍是嚴格模式 默認寬鬆模式  // 嚴格模式:解析構造函數時,必須全部的都須要匹配,不然拋出異常  // 寬鬆模式:使用具備"最接近的模式"進行匹配  // typeDiffWeight:類型差別權重  int typeDiffWeight = (mbd.isLenientConstructorResolution() ?  argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));  // 表明最接近的類型匹配,則選擇做爲構造函數  if (typeDiffWeight < minTypeDiffWeight) {  factoryMethodToUse = candidate;  argsHolderToUse = argsHolder;  argsToUse = argsHolder.arguments;  minTypeDiffWeight = typeDiffWeight;  ambiguousFactoryMethods = null;  }  // 若是具備相同參數數量的方法具備相同的類型差別權重,則收集此類型選項  // 可是,僅在非寬鬆構造函數解析模式下執行該檢查,並顯式忽略重寫方法(具備相同的參數簽名)  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(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") + ".");  }  //返回類型不能爲void  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);  }   if (explicitArgs == null && argsHolderToUse != null) {  mbd.factoryMethodToIntrospect = factoryMethodToUse;  argsHolderToUse.storeCache(mbd, factoryMethodToUse);  }  }   Assert.state(argsToUse != null, "Unresolved factory method arguments");  // 實例化 並返回  bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));  return bw; } 複製代碼

2.1 方法流程圖

instantiateUsingFactoryMethod
instantiateUsingFactoryMethod

2.2 方法分析

  首先這個方法的流程比較長,首先聲明:關於推斷構造函數,這裏暫時不作太多的分析,由於這一部分在後面的文章中經過構造函數實力化對象會詳細介紹。this

  這裏爲了讓文章有頭有尾,一樣也爲了讀文章的時候不懵圈,我試着在這裏將流程簡要的串一下:url

  • ①:首先就是 @Bean 方法對應的 BeanName是什麼? BeanDefinition 是什麼?

    beanName 就是對應的方法名稱,BeanDefinition 就是 ConfigurationClassBeanDefinition

  • ②:而後就是在容器初始化的時候, @Bean 方法生成的 BeanDefinition 是如何解析的?怎麼放到 BeanDefinitionMap 中去的?

    BeanDefinition 的定位加載註冊,方法的入口是 loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)

  • ③:何時觸發 getBean()?

    容器初始化的時候,在 refresh() 方法中的 finishBeanFactoryInitialization(beanFactory); 這裏要注意在調用到 doGetBean(name, null, null, false)argsnull 在實例化的對象的時候用到。

  • ④:如何 getBean()

    for 循環容器中緩存的全部的 beanName 而後 getBean(beanName)

  • ⑤:第五步就是 這篇文章介紹的內容了: 如何經過工廠方法完成Bean的實例化
    • 5.1 實例化初始化 BeanWrapperImpl對象

      這個對象及其重要,後面的依賴注入就是經過這個對象來完成的

    • 5.2 經過 mbd.getFactoryBeanName()獲取 factoryBeanName 經過 factoryBeanName 來區分 靜態非靜態@Bean方法,並作相應處理。
    • 5.3 肯定參數,肯定構造方法
    • 5.4 異常狀況的判斷及處理
    • 5.5 實例化對象

  上述的後 5.2 ~ 5.5的部分就是 instantiateUsingFactoryMethod()方法的重點,這裏不在贅述。至此 @Bean方法的對象的實例化過程已經分析完了。最後,若有什麼問題,還但願各位斧正。恕在下之言,這篇文章可累死老夫了...須要原圖的話,想辦法私聊我吧。

本文使用 mdnice 排版

相關文章
相關標籤/搜索