【spring源码】实例化详解 工厂方法 构造函数

createBeanInstance 是Spring实例化的核心代码,它根据不同的情况会调用四种实例化方法。

  1. obtainFromSupplier 通过Supplier实例化
  2. instantiateUsingFactoryMethod 通过工厂方法
  3. autowireConstructor 用合适的构造函数
  4. instantiateBean 用无参构造函数

第一种很简单,看一下代码就能发现Supplier接口只有一个get方法,就通过这个实例化。
第二第三种比较复杂,也比较相近,本文详细分析。
第四种也很简单,当找不到其它构造函数时,就用无参的,就像兜底的一样。

instantiateUsingFactoryMethod

通过工厂方法进行实例化,简单地想一下,肯定需要下面三个东西

  1. 工厂方法的bean,如果是静态工厂方法的话就不需要这个了。
  2. 要调用的工厂方法
  3. 需要传入的参数

有了上述概念后,来看代码,代码很长很复杂,但是总体上讲就是先解析上面这三个东西,然后进行实例化。

代码入口
// AbstractAutowireCapableBeanFactory
createBeanInstance{
    //...
	if (mbd.getFactoryMethodName() != null) {
	   return instantiateUsingFactoryMethod(beanName, mbd, args);
	}
    //...
}
// AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateUsingFactoryMethod(
      String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

   return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
实际干活的代码

为了更好理解,省略了部分代码,但还是很长…
代码都有详细的注释,并且很明显地分成了三部分,应该能看懂。

// ConstructorResolver
public BeanWrapper instantiateUsingFactoryMethod(
      String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs){
    // 建立一个BeanWrapper
    BeanWrapperImpl bw = new BeanWrapperImpl();
    
//----------------------------------1. 首先确定factoryBean--------------------------------
    
    // 如果是非静态的,获取factoryBean实例,否则null
    Object factoryBean;
    // 工厂类
	Class<?> factoryClass;
    // 非静态false,静态true
	boolean isStatic;
    // ...
//---------------------2. 确定factoryMethod 和 argsToUse(需要传的参数)---------------------
    
    // 用到的factoryMethod
	Method factoryMethodToUse = null;
	ArgumentsHolder argsHolderToUse = null;
	// 需要传入的参数
	Object[] argsToUse = null;
    
  //------------------------------2.1 显式传参 或者 从缓存中拿-------------------------------
    
	// 如果显式传参就不用去解析参数了,但是要通过2.2解析factoryMethodToUse
	if (explicitArgs != null) {
		argsToUse = explicitArgs;
	} else {
        // 从缓存中拿
		Object[] argsToResolve = null;
		synchronized (mbd.constructorArgumentLock) {
            // 获取缓存的方法
			factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
			if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
				// 获取缓存的可以直接使用的参数
				argsToUse = mbd.resolvedConstructorArguments;
				if (argsToUse == null) {
                    // 获取缓存的待解析的参数
					argsToResolve = mbd.preparedConstructorArguments;
				}
			}
		}
        // 解析从未解析的参数: 字符串“3” -> 数字3
		if (argsToResolve != null) {
			argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
		}
	}
    // 如果通过上述步骤argsToUse 和 factoryMethodToUse 都确定了就直接到第三步,否则到2.2
  //-----------------------2.2 argsToUse 或者 factoryMethodToUse还没确定-------------------
    if (factoryMethodToUse == null || argsToUse == null) {
        // 获得所有符合条件的method
		// 条件有两个 1. 如果是静态工厂方法只要static的,否则就只要非static的 2. 是工厂方法
       if (candidates == null) {
				//...
		}
		// 只有一个方法且不需要传参,并且配置文件中也没有定义入参。
		if (candidates.size() == 1 && explicitArgs == null &&
            !mbd.hasConstructorArgumentValues()) {
			// ... 
            // 创建完beanwrapper直接返回
			return bw;
		}
			
		// 如果有很多candidates,先按public,非public排序,再按参数量降序
		if (candidates.size() > 1) { 
			candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
		}
        
        // 从配置文件中解析的参数
		ConstructorArgumentValues resolvedValues = null;
        
		// autowire == "constructor"
		boolean autowiring = (mbd.getResolvedAutowireMode() ==
                                  AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
		// 类型差分数
		int minTypeDiffWeight = Integer.MAX_VALUE;
		// 类型差分数 并列最低的FactoryMethod们
		Set<Method> ambiguousFactoryMethods = null;
		// 配置文件中直接定义 或者 显式传参的数量
		int minNrOfArgs;
        // 解析配置文件中定义的参数
        resolvedValues = new ConstructorArgumentValues();
		minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, 
                                                  resolvedValues);
        // 循环每个方法,找最合适的方法
        for (Method candidate : candidates) {
            // ...
            // 获取解析器
            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
			if (pnd != null) {
                // 获取当前方法需要的参数定义
				paramNames = pnd.getParameterNames(candidate);
			}
            // 根据配置文件中定义好的入参,工厂方法要求的参数,autowiring模式等获得所有参数。
	        // 如果autowiring不是constructor,那配置文件中的入参就得和方法要求的参数完全一致,否则就
            // 会报错
			argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                             paramTypes, paramNames, candidate,
                                             autowiring, candidates.size() == 1);
            // 根据实际获得的参数argsHolder和需要的参数,得到类型差异分
			int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                                  argsHolder.getTypeDifferenceWeight(paramTypes) : 
                                  argsHolder.getAssignabilityWeight(paramTypes));
			// 找最小的typeDiffWeight对应的factoryMethodToUse和argsToUse
    		if (typeDiffWeight < minTypeDiffWeight) {
						factoryMethodToUse = candidate;
						argsHolderToUse = argsHolder;
						argsToUse = argsHolder.arguments;
						minTypeDiffWeight = typeDiffWeight;
						ambiguousFactoryMethods = null;
			}
            if (/*有并列的typeDiffWeight*/){
                ambiguousFactoryMethods.add(candidate);
            }
        }
        // ...
        
        // 存缓存
        if (explicitArgs == null && argsHolderToUse != null) {
			mbd.factoryMethodToIntrospect = factoryMethodToUse;
			argsHolderToUse.storeCache(mbd, factoryMethodToUse);
		}
        
//--------------------------------------3. 实例化-----------------------------------------
        // 根据得到的factoryBean(如果是静态工厂方法就是null),factoryMethodToUse,argsToUse
        // 进行实例化
        bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, 
                                           factoryMethodToUse, argsToUse));
		return bw;
}
总结

主要就是三部分:

  1. 解析工厂类,工厂bean,工厂方法是不是static

  2. 找最合适的工厂方法factoryMethodToUse, 和 需要传入的参数argsToUse

    2.1 根据static或者不是static找到所有的候选方法

    2.2 遍历所有的候选方法,按当前候选方法需要的形参去获得实参(从配置文件中找 或者 可以autowire到的) ,根据形参和实际获得的实参,得到差异分typeDiffWeight,取最小差异分对应的候选方法作为factoryMethodToUse,对应的实参作为argsToUse。

  3. 用工厂bean,factoryMethodToUse,argsToUse进行实例化

理清楚了其实也不是很复杂hhhh

autowireConstructor

这个其实就是低配版的instantiateUsingFactoryMethod。主要少了下面这两部分

  1. 不需要工厂,所以不用解析工厂类,工厂bean
  2. 构造函数没有static的,所以不需要解析isStatic

其它部分基本是一样的。就直接看代码吧,这次放完整的代码了。

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
                              @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

   BeanWrapperImpl bw = new BeanWrapperImpl();
   this.beanFactory.initBeanWrapper(bw);
// --------------------------------1. 确定构造函数 和 入参----------------------------------
   // 构造函数
   Constructor<?> constructorToUse = null;
   ArgumentsHolder argsHolderToUse = null;
   // 传入的参数
   Object[] argsToUse = null;
   // -------------------------------1.1 从缓存中拿------------------------------------
   if (explicitArgs != null) {
      argsToUse = explicitArgs;
   } 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) {
               argsToResolve = mbd.preparedConstructorArguments;
            }
         }
      }
      if (argsToResolve != null) {
         argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
      }
   }
    
  //-----------------------1.2 constructorToUse 或者 argsToUse还没解析出来----------------
   if (constructorToUse == null || argsToUse == null) {
      // Take specified constructors, if any.
      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);
         }
      }

      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;

      int minNrOfArgs;
      if (explicitArgs != null) {
         minNrOfArgs = explicitArgs.length;
      } else {
         ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
         resolvedValues = new ConstructorArgumentValues();
         minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
      }

      AutowireUtils.sortConstructors(candidates);
      int minTypeDiffWeight = Integer.MAX_VALUE;
      Set<Constructor<?>> ambiguousConstructors = null;
      LinkedList<UnsatisfiedDependencyException> causes = null;

      for (Constructor<?> candidate : candidates) {
         int parameterCount = candidate.getParameterCount();

         if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
            // Already found greedy constructor that can be satisfied ->
            // do not look any further, there are only less greedy constructors left.
            break;
         }
         if (parameterCount < minNrOfArgs) {
            continue;
         }

         ArgumentsHolder argsHolder;
         Class<?>[] paramTypes = candidate.getParameterTypes();
         if (resolvedValues != null) {
            try {
               String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
               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 (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;
            }
         } else {
            // Explicit arguments given -> arguments length must match exactly.
            if (parameterCount != explicitArgs.length) {
               continue;
            }
            argsHolder = new ArgumentsHolder(explicitArgs);
         }

         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);
         }
      }

      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);
      }
       
	  // 存缓存
      if (explicitArgs == null && argsHolderToUse != null) {
         argsHolderToUse.storeCache(mbd, constructorToUse);
      }
   }
    
// ----------------------------------2 实例化---------------------------------------------
   Assert.state(argsToUse != null, "Unresolved constructor arguments");
   bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
   return bw;
}
总结

从代码可以看出来它只有两部分了,不需要解析工厂相关的东西了,其它差不多。

instantiateBean

这个就是调用无参构造函数,就不需要各种解析过程了,直接用就完事了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值