Spring容器 —— 深入 bean 的加载(三、创建 bean 实例 —— createBeanInstance)

之前分析了 bean 创建的基本思路,现在我们看看第一步,如何获取一个初步的 bean 框架 BeanWrapper。

createBeanInstance 源码概述

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

		...

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		
		// 如果有工厂方法,则使用工厂方法初始化
		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) {
				// 构造函数自动注入
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// 使用默认构造函数
				return instantiateBean(beanName, mbd);
			}
		}

		// 解析构造函数
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			// 构造函数自动注入
			return autowireConstructor(beanName, mbd, ctors, null);
		}
		
		// 使用默认构造函数
		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

上述源码主要分为两个部分:

  1. 如果是在 RootBeanDefinition 中存在的 factoryMethodName 属性,或者说在配置文件中配置了 factory-method,那么 Spring 会尝试使用 instantiateUsingFactoryMethod(beanName, mbd, args) 方法,根据 RootBeanDefinition 的内容配置生成 bean 实例。
  2. 解析构造函数并进行构造函数实例化。因为一个 bean 对应的类中可能会有多个构造函数,而每个构造函数的参数不同,Spring 根据参数确定使用哪个构造函数,但是判断过程比较消耗性能,所以已经解析过的会从 RootBeanDefinition 的 resolvedConstructorOrFactoryMethod 中获取。

autowireConstructor

该函数对应了带有参数的构造器的 bean 实例化,首先看看源码。

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

		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		Constructor<?> constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;
		
		// explicitArgs 是从 getBean 方法中直接传入的
		// 如果 explicitArgs 不为空,则直接使用
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			// explicitArgs 为空,则尝试从缓存和配置文件中获取对应参数
			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;
					}
				}
			}
			// 若缓存中存在,解析参数类型,如给定构造函数 A(int, int) 则会把配置中的 ("1", "1")
			// 转换为 (1, 1)
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}
		
		// 缓存中没有数据
		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());
				}
				...
			}
			
			// 若只有一个构造函数,并且函数没有参数,则判定为已经解析完成,缓存数据,并实例化
			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);
			}
			
			// 排序构造函数
			// public 函数优先,参数数量降序,非 public 参数数量降序
			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			for (Constructor<?> candidate : candidates) {
				Class<?>[] paramTypes = candidate.getParameterTypes();

				// 已经找到对应的构造函数或者数量上已经不能满足,直接结束寻找
				if (constructorToUse != null && argsToUse != 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 argsHolder;
				if (resolvedValues != null) {
					// 有参数则根据值构造对应参数类型的参数
					try {
						// 从注释获取参数名称
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
						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);
					}
					...
				}
				else {
					// Explicit arguments given -> arguments length must match exactly.
					if (paramTypes.length != 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;
				}
				// 出现相似度一样的构造函数,存入 set
				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);
			}
		}

		// 构造结果放入 BeanWrapper 中
		Assert.state(argsToUse != null, "Unresolved constructor arguments");
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}

上述源码总结一下,可以分为一下几个方面:

  1. 构造函数参数的确定

    • 根据 explicitArgs 参数判断
      如果传入 explicitArgs 参数不为空,则直接用这个参数,作为构造函数参数;explicitArgs 参数来自于 getBean(String name, Object… args) 的 args 部分。
    • 缓存中获取
    • 配置文件中获取
      通过 mbd.getConstructorArgumentValues() 获取配置文件中构造函数的内容。
  2. 构造函数的确定
    遍历所有的待选构造器,根据参数的个数和类型进行相似度判断。

    由于在配置文件中并不只使用参数位置索引的方式去创建,同样还支持指定参数名称进行参数值设置。所以这种情况下还需要获取构造函数的参数名称。Spring 提供了两种获取参数名称的方式:一是通过注解的方式直接获取;二是使用 Spring 中提供的工具类 ParameterNameDiscoverer 来获取。

  3. 根据确定的构造函数转换对应的参数类型
    根据要求的类型,通过 Spring 中的或者自定义的参数转换器进行自动转换。

  4. 构造函数不确定性的验证
    若不同构造函数的参数为父子关系,则会出现相似度一样的两个构造器,这里 Spring 再做了一次验证。

  5. 实例化 bean

instantiateBean

该函数针对没有参数的构造函数进行处理,首先还是先看看源码。

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(
						(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
						getAccessControlContext());
			}
			else {
				// 直接实例化就好了
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

可以发现,该函数直接就开始实例化 bean,相比于 autowireConstructor 少了构造函数的匹配,简单的许多。

实例化策略(InstantiationStrategy)

实例化可以简单地直接用反射,但是 Spring 没有这样做。

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// 如果没有需要覆盖或者动态替换的方法,就不需要使用 CGLIB 进行动态代理
		// 因为可以在创建代理的同时将动态方法织入类中,但是若没有需要动态改变方法的地方,直接反射就行
		// 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) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							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);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

这里主要是对使用反射还是 cglib 动态代理进行了选择,如果类中没有需要动态改变的方法,即没有使用 replace 或者 lookup 的配置方法,就可以直接使用反射。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值