Bean loading of Spring Ioc source code analysis (5): instantiating beans

In the last article, Spring Ioc source code analysis of Bean loading (4): In createBean() , we analyzed the doCreateBean()general process of the method. In this article, we will analyze the method of instantiating beanscreateBeanInstance() in detail , and the remaining steps will be in other articles. introduce.

In short:
the essence of instantiating a Bean is actually to find a suitable constructor, and then newInstance()instantiate the Bean by calling the constructor.
It seems that the process of instantiating a bean is very simple, but in fact Spring has spent a lot of experience finding a suitable constructor.

instantiate beans

At doCreateBean()code <2>, there is a line of code instanceWrapper = createBeanInstance(beanName, mbd, args);
This code is the process of instantiating the bean.
Let's track it in and take a look:

//AbstractAutowireCapableBeanFactory.java

//创建Bean的实例对象
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		//解析beanName 为 class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		//检查确认Bean是可实例化的
		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());
		}
                 //如果存在 Supplier 回调,则使用给定的回调方法初始化策略
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
                //使用 FactoryBean 的 factory-method 来创建,支持静态工厂和实例工厂
		if (mbd.getFactoryMethodName() != null)  {
			//调用工厂方法实例化
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		//构造函数自动注入进行实例化
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
				    // 如果已缓存的解析的构造函数或者工厂方法不为空,则可以利用构造函数解析
			       	// 因为需要根据参数确认到底使用哪个构造函数,该过程比较消耗性能,所有采用缓存机制
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		// 如果已经解析过,不需要再次解析
		if (resolved) {
			if (autowireNecessary) {
				//构造函数自动注入进行实例化
				//一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数进行 bean 的实例化
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//使用默认的无参构造方法实例化
				return instantiateBean(beanName, mbd);
			}
		}

		// Need to determine the constructor...
		//需要根据参数解析构造函数
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
			//使用容器的自动装配特性,调用匹配的构造方法实例化
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
		//使用默认的无参构造方法实例化
		return instantiateBean(beanName, mbd);
	}

In this code, Spring divides Bean instances into 4 ways:

  • Supplier callback
  • Factory method initialization
  • Constructor auto-injection initialization
  • Default no-argument constructor initialization

1.1, Supplier callback

If there is a Supplier callback, call the obtainFromSupplier(Supplier<?> instanceSupplier, String beanName)method to initialize it.
Supplier is an interface, defined as follows:

public interface Supplier<T> {

    T get();
    
}

What does this interface do? Used to specify a callback for bean creation. If we set such a callback, then other constructors or factory methods will be useless. The
setting is in the constructor of the BeanDefinition, such as:

// RootBeanDefinition.java

public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {
	super();
	setBeanClass(beanClass);
	setScope(scope);
	// 设置 instanceSupplier 属性
	setInstanceSupplier(instanceSupplier);
}

1.2, factory method initialization

If a factory method exists, use the factory method for initialization. This part of the code is very long and complex, so I won't go into details here.

1.3, the constructor automatically injects initialization

First judge the cache. If the cache exists (resolved==true), that is, it has been parsed, then the parsed one will be used directly. Otherwise, the constructor is resolved first, and then the initialization is automatically injected through the constructor.

1.3.1、autowireConstructor()

autowireConstructor()This initialization method can be simply understood as initializing the Bean object through a constructor with parameters. The instantiation process with parameters is quite complicated. Because of this uncertainty, a lot of work has been done on judging the corresponding parameters.
The code snippet is as follows:

//AbstractAutowireCapableBeanFactory.java

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

	// 封装 BeanWrapperImpl 对象,并完成初始化
	BeanWrapperImpl bw = new BeanWrapperImpl();
	this.beanFactory.initBeanWrapper(bw);

	Constructor<?> constructorToUse = null;// 最终使用的构造函数
	ArgumentsHolder argsHolderToUse = null;// 构造参数
	Object[] argsToUse = null;// 构造参数

	// 判断有无显式指定参数,如果有则优先使用,如 xxxBeanFactory.getBean("teacher", "李华",3);
<1>	if (explicitArgs != null) {
		argsToUse = explicitArgs;
	}
	// 没有显式指定参数,则解析配置文件中的参数
<2>	else {
		Object[] argsToResolve = null;
		synchronized (mbd.constructorArgumentLock) {
			// 优先尝试从缓存中获取,spring对参数的解析过程是比较复杂也耗时的,所以这里先尝试从缓存中获取已经解析过的构造函数参数
			constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
                        //如果构造方法和参数都不为Null
			if (constructorToUse != null && mbd.constructorArgumentsResolved) {
				// Found a cached constructor...
				// 获取缓存中的构造参数
				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, constructorToUse, argsToResolve);
		}
	}

	// 缓存不存在,则需要解析构造函数参数,以确定使用哪一个构造函数来进行实例化
<3>	if (constructorToUse == null) {
		// Need to resolve the constructor.
		boolean autowiring = (chosenCtors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		// 用于承载解析后的构造函数参数的值
		ConstructorArgumentValues resolvedValues = null;

		//参数个数
<4>		int minNrOfArgs;
		if (explicitArgs != null) {
			minNrOfArgs = explicitArgs.length;
		}
		else {
			// 从 BeanDefinition 中获取构造参数,也就是从配置文件中提取构造参数
			ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
			resolvedValues = new ConstructorArgumentValues();
			// 能解析到的参数个数
			minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
		}

		// Take specified constructors, if any.
		//使用指定的构造函数,如果有的话
<5>		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);
			}
		}

		// 对所有构造函数进行排序,public 且 参数最多的构造函数会排在第一位
<6>		AutowireUtils.sortConstructors(candidates);
		int minTypeDiffWeight = Integer.MAX_VALUE;
		//模棱两可的构造函数集合
		Set<Constructor<?>> ambiguousConstructors = null;
		LinkedList<UnsatisfiedDependencyException> causes = null;

		// 迭代所有构造函数,解析确定使用哪一个构造函数
<7>		for (Constructor<?> candidate : candidates) {
			// 获取该构造函数的参数类型
<8>			Class<?>[] paramTypes = candidate.getParameterTypes();

			// 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数,则终止。
			// 因为,已经按照参数个数降序排列了
			if (constructorToUse != null && argsToUse.length > paramTypes.length) {
				// Already found greedy constructor that can be satisfied ->
				// do not look any further, there are only less greedy constructors left.
				break;
			}
			// 参数个数不等,跳过
			if (paramTypes.length < minNrOfArgs) {
				continue;
			}

			// 参数持有者 ArgumentsHolder 对象
			ArgumentsHolder argsHolder;
<9>			if (resolvedValues != null) {
				try {
					// 获取注解上的参数名称 by @ConstructorProperties
					String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
					if (paramNames == null) {
						ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
						if (pnd != null) {
							// 获取指定构造函数的参数名称
							paramNames = pnd.getParameterNames(candidate);
						}
					}
					// 根据构造函数和构造参数,创建参数持有者 ArgumentsHolder 对象
					argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
							getUserDeclaredConstructor(candidate), autowiring);
				}
				catch (UnsatisfiedDependencyException ex) {
					if (this.beanFactory.logger.isTraceEnabled()) {
						this.beanFactory.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 (paramTypes.length != explicitArgs.length) {
					continue;
				}
				// 根据 getBean()传入的 explicitArgs ,创建 ArgumentsHolder 对象
				argsHolder = new ArgumentsHolder(explicitArgs);
			}

			//通过构造函数参数差异值对比,得出最适合使用的构造函数
				// isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式(默认宽松)
				// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
				// 宽松模式:使用具有"最接近的模式"进行匹配
			int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
					argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
			// Choose this constructor if it represents the closest match.
			// 如果它代表着当前最接近的匹配则选择其作为构造函数
			//差异值越小,越匹配,每次和分数最小的去比较
<10>			if (typeDiffWeight < minTypeDiffWeight) {
				constructorToUse = candidate;
				argsHolderToUse = argsHolder;
				argsToUse = argsHolder.arguments;
				minTypeDiffWeight = typeDiffWeight;
				ambiguousConstructors = null;
			}
			// 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为
	                // 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructors
			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);
		}
            
                 // 将解析的构造函数、参数 加入缓存
<11>		if (explicitArgs == null) {
			/*
                	 * 缓存相关信息,比如:
                	 *   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
                	 *   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
                	 *   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
                	 *
                	 * 这些信息可用在其他地方,用于进行快捷判断
                	 */
			argsHolderToUse.storeCache(mbd, constructorToUse);
		}
	}

	try {
		//获取Bean的初始化策略
		final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
		Object beanInstance;

		//创建 Bean 对象
<12>		if (System.getSecurityManager() != null) {
			final Constructor<?> ctorToUse = constructorToUse;
			final Object[] argumentsToUse = argsToUse;
			beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
					strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
					beanFactory.getAccessControlContext());
		}
		else {
			beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
		}

		//设置到 bw 中
		bw.setBeanInstance(beanInstance);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean instantiation via constructor failed", ex);
	}
	}

The code is very long, but don't panic, let's analyze it step by step:

  • At <1>, it is judged whether the construction parameters are explicitly specified
  • At <2>, if no parameter is explicitly specified, it is obtained from the cache
  • At <3>, the cache does not exist, resolve the constructor parameters
  • At <4>, get the number of construction parameters
  • At <5>, get all constructors
  • At <6>, sort all constructors
  • At <7>, traverse all construction methods
  • At <8>, check the construction method by parameter
  • At <9>, create the parameter holder ArgumentsHolder
  • <10>, filter out the conforming construction method
  • At <11>, add the parsed constructor and parameters to the cache
  • <12>, instantiate the Bean object
1.3.1.1. Determine whether the construction parameters are explicitly specified
  • explicitArgs
    外部传入的指定构造参数
  • argsToUse
    要使用的构造参数

explicitArgs refers to the specified construction parameters passed in from the outside. For example xxxBeanFactory.getBean("teacher", "李华",3), (Li Hua and 3) are the specified parameters passed in.
argsToUse is the construction parameter we want to use when instantiating. Here it is judged that if explicitArgs is not null, assign explicitArgs to argsToUse.

1.3.1.2. If no parameter is explicitly specified, it is obtained from the cache
Object[] argsToResolve = null;
	synchronized (mbd.constructorArgumentLock) {
		// 优先尝试从缓存中获取,spring对参数的解析过程是比较复杂也耗时的,所以这里先尝试从缓存中获取已经解析过的构造函数参数
		constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
		//如果构造方法和参数都不为Null
		if (constructorToUse != null && mbd.constructorArgumentsResolved) {
			// Found a cached constructor...
			// 获取缓存中的构造参数
			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, constructorToUse, argsToResolve);
	}

First mbd.resolvedConstructorOrFactoryMethodget the constructor from the cache, and if there are constructors and parameters in the cache, parse the constructor parameters.
Because the construction parameters in the cache are not necessarily final values, such as the constructor A(int ,int ) of a given method, after passing this method, ("1", "1") in the configuration file will be converted to ( 1,1)

1.3.1.3, the cache does not exist, resolve the constructor parameters

If the cache does not exist, the constructor parameters need to be resolved to determine which constructor to use for instantiation

1.3.1.4, get the number of construction parameters
        //参数个数
	int minNrOfArgs;
	if (explicitArgs != null) {
		minNrOfArgs = explicitArgs.length;
	}
	else {
		// 从 BeanDefinition 中获取构造参数,也就是从配置文件中提取构造参数
		ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
		resolvedValues = new ConstructorArgumentValues();
		// 能解析到的参数个数
		minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
	}
  • If explicitArgs is not null
    , get it directly.

  • For null
    , you need to parse the parameters specified in the BeanDefinition constructor
    and get the number of parameters that can be parsed

1.3.1.5. Get all constructors

First try to obtain the specified constructor, if not, use reflection to obtain all constructors

1.3.1.6. Sort all constructors

The main purpose of sorting is to more easily find the most matching construction method, because the confirmation of the construction method is confirmed according to the number of parameters. The sorting rules are as follows: first by public/non-public constructors in ascending order, and then by number of constructor parameters in descending order.

1.3.1.7. Traverse all constructors

Traverse all construction methods and filter out the most matching one

1.3.1.8. Construction method by parameter verification
// 获取该构造函数的参数类型
	Class<?>[] paramTypes = candidate.getParameterTypes();

	///这里的判断构造方法和构造方法参数 都不是空,又由于之前对构造方法做了排序。所以在使用的参数的个数已经大于当前构造方法的参数个数的时候,实际上已经取到了想要的构造方法。
	if (constructorToUse != null && argsToUse.length > paramTypes.length) {
		// Already found greedy constructor that can be satisfied ->
		// do not look any further, there are only less greedy constructors left.
		break;
	}
	// 当前的构造参数个数小于我们要求的个数,跳过
	if (paramTypes.length < minNrOfArgs) {
		continue;
	}

This code is not complicated. The first if is the break branch. If the condition is met, it will jump out of the for loop. This means that the most matching construction method has been found.
EX: Assuming that there is now a set of constructors sorted according to the above sorting rules, the sorting results are as follows:

  
     1. public Hello(Object, Object, Object)
     2. public Hello(Object, Object)
     3. public Hello(Object)
     4. protected Hello(Integer, Object, Object, Object)
     5. protected Hello(Integer, Object, Object)
     6. protected Hello(Integer, Object)

Since it is sorted in descending order, it will first match construction method 1 and find that argsToUse.length > paramTypes.length

The second if is to quickly judge whether the current construction method meets our requirements.

  • paramTypes
    The number of parameters of the current constructor
  • minNrOfArgs
    The number of parameters of the construction method we require If the current number of construction parameters is less than the number we require, it means that the current construction method does not meet our requirements, and continue directly
1.3.1.9. Create parameter holder ArgumentsHolder
        // 参数持有者 ArgumentsHolder 对象
	ArgumentsHolder argsHolder;
	if (resolvedValues != null) {
		try {
			// 获取注解上的参数名称 by @ConstructorProperties
			String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
			if (paramNames == null) {
				// ParameterNameDiscoverer 是用于解析方法和构造函数的参数名称的接口,为参数名称探测器
				ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
				if (pnd != null) {
					// 获取指定构造函数的参数名称
					paramNames = pnd.getParameterNames(candidate);
				}
			}
			// 根据构造函数和构造参数,创建参数持有者 ArgumentsHolder 对象
			argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
					getUserDeclaredConstructor(candidate), autowiring);
		}
		catch (UnsatisfiedDependencyException ex) {
			if (this.beanFactory.logger.isTraceEnabled()) {
				this.beanFactory.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 (paramTypes.length != explicitArgs.length) {
			continue;
		}
		// 根据 getBean()传入的 explicitArgs ,创建 ArgumentsHolder 对象
		argsHolder = new ArgumentsHolder(explicitArgs);
	}

There are two main logics here:

  • resolvedValues ​​!= null
    means that the specified construction parameters are not displayed
  • resolvedValues ​​== null
    shows that the construction parameters are specified

The first branch:
first @ConstructorPropertiesobtain the name of the construction parameter through the annotation, if not, then ParameterNameDiscovererobtain it, and finally create the ArgumentsHolder
Second branch:
directly use the displayed incoming construction parameter explicitArgs to create a new ArgumentsHolder

Wrap the parameter into an ArgumentsHolderobject . This object is used to hold parameters, we call it the parameter holder. In this process, the construction parameters are parsed again, and type conversion is performed, such as converting the string in the configuration file into the required int.
After wrapping the object into an ArgumentsHolder object, we can use it for constructor matching. Matching is divided into strict mode and relaxed mode:

  • Strict mode: When parsing a constructor, all parameters must match, otherwise an exception is thrown.

  • Loose Mode: From the ambiguous construction methods, choose the closest.
    The basis for the judgment is to obtain the type difference weight (typeDiffWeight) according to the isLenientConstructorResolutionproperties (this parameter is passed when we construct the AbstractBeanDefinition object).

1.3.1.10. Screen out the conforming construction method
//通过构造函数参数差异值对比,得出最适合使用的构造函数
		// isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式(默认宽松)
		// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
		// 宽松模式:使用具有"最接近的模式"进行匹配
	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;
	}
	// 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为
	// 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入ambiguousConstructors
	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);
			}

First, calculate the difference value of the current construction method typeDiffWeight, compare it with the smallest score each time, filter out the smallest difference value, and finally compare the most matching construction method.
If the difference value is greater than the minimum difference value, it is added to the candidate setambiguousConstructors , which I call the ambiguous construction method, and this set is used in the "relaxed mode".

So far, all construction methods have been traversed. If the constructor is still not filtered out, an exception is thrown.
Throws an exception if the ambiguous constructor is not null, but the mode is strict.

1.3.1.11. Add the parsed constructor and parameters to the cache
// 将解析的构造函数、参数 加入缓存
if (explicitArgs == null) {
	/*
	 * 缓存相关信息,比如:
	 *   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
	 *   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
	 *   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
	 *
	 * 这些信息可用在其他地方,用于进行快捷判断
	 */
	argsHolderToUse.storeCache(mbd, constructorToUse);
	}

Keep following:

 // ArgumentsHolder.java
        public final Object rawArguments[];

	public final Object arguments[];

	public final Object preparedArguments[];

public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
	synchronized (mbd.constructorArgumentLock) {
		mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
		mbd.constructorArgumentsResolved = true;
		if (this.resolveNecessary) {
			mbd.preparedConstructorArguments = this.preparedArguments;
		}
		else {
			mbd.resolvedConstructorArguments = this.arguments;
		}
	}
		}

I believe that everyone here should be familiar with these parameters such as andresolvedConstructorOrFactoryMethod . As you can imagine, when judging whether the cache exists or not, it is judged by these parameters.resolvedConstructorArguments

1.3.1.12. Instantiate the Bean object

strategy.instantiate

//SimpleInstantiationStrategy.java

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
		final Constructor<?> ctor, @Nullable Object... args) {
	// 没有方法覆盖,直接使用反射实例化即可
	if (!bd.hasMethodOverrides()) {
		if (System.getSecurityManager() != null) {
			// use own privileged to change accessibility (when security is on)
			// 设置构造方法,可访问
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				ReflectionUtils.makeAccessible(ctor);
				return null;
			});
		}
		// 通过 BeanUtils 直接使用构造函数实例化 Bean 对象
		return (args != null ? BeanUtils.instantiateClass(ctor, args) : BeanUtils.instantiateClass(ctor));
	}
	else {
		// 使用 CGLIB 创建代理对象
		//方法覆盖,在调用目标方法的时候,对调用过程进行拦截,调用实现增强功能的拦截器,返回原来实例的代理
		//所以要用cglib动态代理
		return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
	}
	}

BeanUtils.instantiateClass(ctor, args)

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			// 设置构造方法,可访问
			ReflectionUtils.makeAccessible(ctor);
			// 使用构造方法,创建对象 newInstance
			return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
					KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
		}
	}

1.3.2. Graphical process

Because this code is quite complicated, I drew a branch flow chart (explicitArgs=null) for easy understanding.

1.3, default no-argument constructor initialization

After the destruction of the source code initialized by the parameterized construction method, if you look at the source code without parameters, you will find that it is much simpler.

return instantiateBean(beanName, mbd);

Keep following:

//使用默认的无参构造方法实例化Bean对象
	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
	try {
		Object beanInstance;
		final BeanFactory parent = this;
		//获取系统的安全管理接口,JDK标准的安全管理API
		if (System.getSecurityManager() != null) {
			//这里是一个匿名内置类,根据实例化策略创建实例对象
			beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
					getInstantiationStrategy().instantiate(mbd, beanName, parent),
					getAccessControlContext());
		}
		else {
			//将实例化的对象封装起来
			beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
		}
		BeanWrapper bw = new BeanWrapperImpl(beanInstance);
		initBeanWrapper(bw);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
	}
	}

After reading the source code of the initialization of the construction method with parameters, and then looking at the one without parameters, I found that the code is really too simple, and there is no complicated logic to determine the construction parameters and construction methods.

instantiate(mbd, beanName, parent)

//SimpleInstantiationStrategy.java

//使用初始化策略实例化Bean对象
	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
	// Don't override the class with CGLIB if no overrides.
	// 没有覆盖,直接使用反射实例化即可
	if (!bd.hasMethodOverrides()) {
		Constructor<?> constructorToUse;
		synchronized (bd.constructorArgumentLock) {
			//从缓存中获取对象的构造方法或工厂方法
			constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
			//缓存没有
			if (constructorToUse == null) {
				//使用JDK的反射机制,判断要实例化的Bean是否是接口
				final Class<?> clazz = bd.getBeanClass();
				if (clazz.isInterface()) {
					throw new BeanInstantiationException(clazz, "Specified class is an interface");
				}
				try {
					if (System.getSecurityManager() != null) {
						//这里是一个匿名内置类,使用反射机制获取Bean的构造方法
						constructorToUse = AccessController.doPrivileged(
								(PrivilegedExceptionAction<Constructor<?>>) () -> clazz.getDeclaredConstructor());
					}
					else {
						constructorToUse =	clazz.getDeclaredConstructor();
					}
					bd.resolvedConstructorOrFactoryMethod = constructorToUse;
				}
				catch (Throwable ex) {
					throw new BeanInstantiationException(clazz, "No default constructor found", ex);
				}
			}
		}
		//使用BeanUtils实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化
		return BeanUtils.instantiateClass(constructorToUse);
	}
	else {
		// Must generate CGLIB subclass.
		//有方法覆盖,使用CGLIB来实例化对象
		//方法覆盖,在调用目标方法的时候,对调用过程进行拦截,调用实现增强功能的拦截器,返回原来实例的代理
		//所以要用cglib动态代理
		return instantiateWithMethodInjection(bd, beanName, owner);
	}
	}

A few simple steps:

  • Determine whether there is a method to cover
  • Attempt to get constructor from cache
  • Check if the bean is an interface
  • Use reflection to get the default constructor
  • Instantiate with BeanUtils

BeanUtils. instantiateClass(constructorToUse)

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
	Assert.notNull(ctor, "Constructor must not be null");
	try {
		// 设置构造方法,可访问
		ReflectionUtils.makeAccessible(ctor);
		// 使用构造方法,创建对象 newInstance
		return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
				KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
	}
	catch (InstantiationException ex) {
		throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
	}
	catch (IllegalAccessException ex) {
		throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
	}
	catch (IllegalArgumentException ex) {
		throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
	}
	catch (InvocationTargetException ex) {
		throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
	}
	}

Set up kiss access first, then newInstance()create the object.

总结

For the createBeanInstance()method , he selects the appropriate instantiation strategy to create an instance object for the bean. The specific strategies are:

  • Supplier callback method

  • Factory method initialization

  • Constructor auto-injection initialization

  • Default constructor injection.

Among them, factory method initialization and constructor automatic injection initialization are the most complicated, mainly because of the uncertainty of constructors and construction parameters. Spring needs to spend a lot of energy to determine constructors and construction parameters. , you can directly select the instantiation strategy.

Of course, when instantiating, it will be based on whether there is a need to override or dynamically replace the method, because if there is coverage or weaving, you need to create a dynamic proxy to weave the method. At this time, you can only choose the way of CGLIB to instantiate, otherwise You can directly use the reflection method, which is convenient and quick.

Finally:
the code for instantiating the bean has been analyzed here. This part of the source code seems to be difficult. I panicked when I read it, and it was very tiring to write, but I will continue to write it. You will find that when you study After understanding a piece of source code, the sense of achievement is really cool 0.0

PS: It's not easy to code words, I hope everyone will like it more, and give my little brother some motivation TT

Reference: Official Account - Taro Source Code

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324216898&siteId=291194637