Spring bean 构造函数参数依赖注入分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/andy_zhang2007/article/details/88761060

1. 构造函数参数依赖的例子


@Component
public class BeanA {
    // 省略实现
    // ...     
}

@Component
public class BeanB {
    BeanA a;

    // 注意,这里可以不使用 @AutoWired 等注解就会导致Spring的依赖注入
    public BeanB(BeanA a) {
        this.a = a;
    }
}

2. 构造函数参数依赖解析过程分析

在该例子中,当从容器首次获取beanB时,会导致beanB的实例化,该实例化会调用类BeanB的构造函数BeanB(BeanA a),进而会导致beanA的实例化。该动作发生的位置如下 :

	// AbstractAutowireCapableBeanFactory 类代码片段
    
	/**
	 * 根据指定的bean定义 mbd 创建指定名称为 beanName 的 bean
	 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
	 * factory method, constructor autowiring, or simple instantiation.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean 
	 * @param args explicit arguments to use for constructor or factory method invocation 通常为空
	 * @return a BeanWrapper for the new instance
	 * @see #obtainFromSupplier
	 * @see #instantiateUsingFactoryMethod
	 * @see #autowireConstructor
	 * @see #instantiateBean
	 */
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, 
		@Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
        // 确保在这里先获取 bean class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) 
			&& !mbd.isNonPublicAccessAllowed()) {
        // beanClass 已经确定,但是没有使用 public 修饰,不允许 public 访问,
        // 则抛出异常 BeanCreationException
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
			"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
        // 目标 bean 由 instanceSupplier 提供的情况
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		if (mbd.getFactoryMethodName() != null) {
         // 目标 bean 由 factory method 提供的情况
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		// 重复创建同一个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 {
				// 使用缺省构造函数实例化bean
				// 缺省构造函数也就是一般所说的无参构造函数
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		// 使用 BeanPostProcessors 决定使用创建bean的候选构造函数
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// 使用构造函数自动装配方式实例化bean
			// 构造函数的参数会被作为依赖被解析和注入
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			// 使用构造函数自动装配方式实例化bean
			// 构造函数的参数会被作为依赖被解析和注入
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		// 使用缺省构造函数实例化bean
		// 缺省构造函数也就是一般所说的无参构造函数
		return instantiateBean(beanName, mbd);
	}

从上面的代码可见,如果bean创建需要使用带参数的构造函数,也就是类似例子BeanB(BeanA a)情况,则在目标bean实例创建的过程中,就会通过方法autowireConstructor使用相应的构造函数进行实例的创建,而在此过程中,首先就需要将构造函数的参数作为依赖被解析。具体我们来看autowireConstructor的实现 :


	/**
	 * "autowire constructor" (with constructor arguments by type) behavior.
	 * Also applied if explicit constructor argument values are specified,
	 * matching all remaining arguments with beans from the bean factory.
     * 
     * This corresponds to constructor injection: In this mode, a Spring
	 * bean factory is able to host components that expect constructor-based
	 * dependency resolution.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @param ctors the chosen candidate constructors
	 * @param explicitArgs argument values passed in programmatically via the getBean method,
	 * or  null if none (-> use constructor argument values from bean definition)
	 * @return a BeanWrapper for the new instance
	 */
	protected BeanWrapper autowireConstructor(
		   String beanName, RootBeanDefinition mbd, 
            @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {

		return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
	}

从该方法可见,此过程是使用当前容器BeanFactory构造了一个ConstructorResolver,然后调用委托该ConstructorResolver对象的方法autowireConstructor完成最终的构造函数依赖解析和目标bean的创建。

ConstructorResolver#autowireConstructor对目标bean的创建,又可以基本上分为两个步骤:

  1. 解析构造函数参数依赖的bean
  2. 调用相应的构造函数创建目标bean

而上面的第一步如下所示 :

	/**
	 * Create an array of arguments to invoke a constructor or factory method,
	 * given the resolved constructor argument values.
	 */
	private ArgumentsHolder createArgumentArray(
			String beanName, RootBeanDefinition mbd, 
			@Nullable ConstructorArgumentValues resolvedValues,
			BeanWrapper bw, Class<?>[] paramTypes, 
			@Nullable String[] paramNames, Executable executable,
			boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {

		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
		TypeConverter converter = (customConverter != null ? customConverter : bw);

		ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
		Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);

		for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
			Class<?> paramType = paramTypes[paramIndex];
			String paramName = (paramNames != null ? paramNames[paramIndex] : "");
			// Try to find matching constructor argument value, either indexed or generic.
			ConstructorArgumentValues.ValueHolder valueHolder = null;
			if (resolvedValues != null) {
				valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, 
					paramName, usedValueHolders);
				// If we couldn't find a direct match and are not supposed to autowire,
				// let's try the next generic, untyped argument value as fallback:
				// it could match after type conversion (for example, String -> int).
				if (valueHolder == null && (!autowiring 
					|| paramTypes.length == resolvedValues.getArgumentCount())) {
					valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
				}
			}
			if (valueHolder != null) {
				// We found a potential match - let's give it a try.
				// Do not consider the same value definition multiple times!
				usedValueHolders.add(valueHolder);
				Object originalValue = valueHolder.getValue();
				Object convertedValue;
				if (valueHolder.isConverted()) {
					convertedValue = valueHolder.getConvertedValue();
					args.preparedArguments[paramIndex] = convertedValue;
				}
				else {
					MethodParameter methodParam = 
						MethodParameter.forExecutable(executable, paramIndex);
					try {
						convertedValue = converter.convertIfNecessary(originalValue, 
								paramType, methodParam);
					}
					catch (TypeMismatchException ex) {
						throw new UnsatisfiedDependencyException(
							mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
							"Could not convert argument value of type [" +
									ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
									"] to required type [" + paramType.getName() + "]: " + 
									ex.getMessage());
					}
					Object sourceHolder = valueHolder.getSource();
					if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
						Object sourceValue = 
							((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
							
						args.resolveNecessary = true;
						args.preparedArguments[paramIndex] = sourceValue;
					}
				}
				args.arguments[paramIndex] = convertedValue;
				args.rawArguments[paramIndex] = originalValue;
			}
			else {
				MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
				// No explicit match found: we're either supposed to autowire or
				// have to fail creating an argument array for the given constructor.
				if (!autowiring) {
					throw new UnsatisfiedDependencyException(
						mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
						"Ambiguous argument values for parameter of type [" + paramType.getName() +
						"] - did you specify the correct bean references as arguments?");
				}
				try {
                 // 这里调用 resolveAutowiredArgument 方法解析一个构造函数参数对应的依赖bean
					Object autowiredArgument = resolveAutowiredArgument(
							methodParam, beanName, autowiredBeanNames, converter, fallback);
					args.rawArguments[paramIndex] = autowiredArgument;
					args.arguments[paramIndex] = autowiredArgument;
					args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
					args.resolveNecessary = true;
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(
							mbd.getResourceDescription(), beanName, 
							new InjectionPoint(methodParam), ex);
				}
			}
		}

		for (String autowiredBeanName : autowiredBeanNames) {
			this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
			if (logger.isDebugEnabled()) {
				logger.debug("Autowiring by type from bean name '" + beanName +
				"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
				" to bean named '" + autowiredBeanName + "'");
			}
		}

		return args;
	}

而上面的方法又会使用如下方法解析每个构造函数参数的值 :

	@Nullable
	protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
			@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {

		Class<?> paramType = param.getParameterType();
		if (InjectionPoint.class.isAssignableFrom(paramType)) {
			InjectionPoint injectionPoint = currentInjectionPoint.get();
			if (injectionPoint == null) {
				throw new IllegalStateException("No current InjectionPoint available for " + param);
			}
			return injectionPoint;
		}
		try {
            // 最终通过 beanFactory.resolveDependency 获取当前方法参数所对应的依赖bean
			return this.beanFactory.resolveDependency(
										new DependencyDescriptor(param, true), 
										beanName, 
										autowiredBeanNames, 
										typeConverter);
		}
		catch (NoUniqueBeanDefinitionException ex) {
			throw ex;
		}
		catch (NoSuchBeanDefinitionException ex) {
			if (fallback) {
				// Single constructor or factory method -> let's return an empty array/collection
				// for e.g. a vararg or a non-null List/Set/Map parameter.
				if (paramType.isArray()) {
					return Array.newInstance(paramType.getComponentType(), 0);
				}
				else if (CollectionFactory.isApproximableCollectionType(paramType)) {
					return CollectionFactory.createCollection(paramType, 0);
				}
				else if (CollectionFactory.isApproximableMapType(paramType)) {
					return CollectionFactory.createMap(paramType, 0);
				}
			}
			throw ex;
		}
	}

从上面的分析可以看出,构造函数参数所对应的依赖最终由beanFactory.resolveDependency最终解析得到。关于beanFactory.resolveDependency是如何工作的,你可以参考 : “Spring 依赖解决过程分析”。

猜你喜欢

转载自blog.csdn.net/andy_zhang2007/article/details/88761060
今日推荐