版权声明:本文为博主原创文章,未经博主允许不得转载。 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
的创建,又可以基本上分为两个步骤:
- 解析构造函数参数依赖的
bean
- 调用相应的构造函数创建目标
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 依赖解决过程分析”。