概述
依赖注入是Spring
框架的基本能力。而完成一次依赖注入,概念上又可以分为两步:
- 找到依赖
- 注入依赖
在这两个步骤中,找到依赖是相对复杂的一个步骤,而一旦找到依赖,注入依赖只是一个简单的设置动作。本文我们就结合源代码分析一下Spring
是如何找到依赖的,也就我们所说的依赖解决的过程。
源代码分析
1. 框架对依赖解决的定义
具体来讲,Spring
框架首先对依赖注入有接口层面的定义,如下所示 :
// 接口 : AutowireCapableBeanFactory
/**
* Resolve the specified dependency against the beans defined in this factory.
* @param descriptor the descriptor for the dependency (field/method/constructor)
* @param requestingBeanName the name of the bean which declares the given dependency
* @return the resolved object, or null if none found
* @throws NoSuchBeanDefinitionException if no matching bean was found
* @throws NoUniqueBeanDefinitionException if more than one matching bean was found
* @throws BeansException if dependency resolution failed for any other reason
* @since 2.5
* @see #resolveDependency(DependencyDescriptor, String, Set, TypeConverter)
*/
@Nullable
Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName)
throws BeansException;
/**
* Resolve the specified dependency against the beans defined in this factory.
* @param descriptor the descriptor for the dependency (field/method/constructor)
* @param requestingBeanName the name of the bean which declares the given dependency
* @param autowiredBeanNames a Set that all names of autowired beans (used for
* resolving the given dependency) are supposed to be added to
* @param typeConverter the TypeConverter to use for populating arrays and collections
* @return the resolved object, or null if none found
* @throws NoSuchBeanDefinitionException if no matching bean was found
* @throws NoUniqueBeanDefinitionException if more than one matching bean was found
* @throws BeansException if dependency resolution failed for any other reason
* @since 2.5
* @see DependencyDescriptor
*/
@Nullable
Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter)
throws BeansException;
从上面代码可见,接口AutowireCapableBeanFactory
定义了两个多态方法resolveDependency
用于解析依赖。这些方法涉及了如下参数:
-
DependencyDescriptor descriptor
对当前将要注入的依赖的描述符,比如这是一个成员属性依赖,构造函数参数依赖或者成员方法参数依赖等等。
关于
DependencyDescriptor
,你可以参考我的另外一篇文章"Spring 工具类 DependencyDescriptor"。 -
String requestingBeanName
定义该依赖的
bean
的名称,也就是将要注入的依赖bean
的使用方bean
的名称。 -
Set<String> autowiredBeanNames
对于所找到的依赖
bean
,如果使用者需要知道它们的名字,可以传进去这样一个集合,然后依赖解析过程会讲这些依赖bean
的名称放入该集合。当然,也设置该参数为null
让依赖解析过程不执行此动作。 -
TypeConverter typeConverter
如果要处理数组或者集合类型的依赖注入,使用
typeConverter
进行必要的类型转换。
另外异常方面:
1. 如果针对某个必要依赖找不到匹配的bean
会抛出异常NoSuchBeanDefinitionException
,
2. 如果针对某个依赖找到多个bean
会抛出异常NoUniqueBeanDefinitionException
,
3. 如果是其他原因依赖解析失败,则会抛出异常BeansException
。
2. 框架对依赖解决的实现
2.1 resolveDependency(DependencyDescriptor,String)
的实现
在具体实现上,Spring
框架其实是将resolveDependency(DependencyDescriptor,String)
通过resolveDependency(DependencyDescriptor,String,Set<String>,TypeConverter)
实现,如下所示:
// 类 AbstractAutowireCapableBeanFactory 代码片段
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName) throws BeansException {
return resolveDependency(descriptor, requestingBeanName, null, null);
}
只是将第三个参数Set<String> autowiredBeanNames
和第四个参数TypeConverter typeConverter
都设置为null
。
接下来,我们来看resolveDependency(DependencyDescriptor,String,Set<String>,TypeConverter)
的具体实现。
2.2 resolveDependency(DependencyDescriptor,String,Set<String>,TypeConverter)
的实现
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor,
@Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter) throws BeansException {
// 为依赖描述符设置参数名称发现器
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 下面的 if-else 语句根据 descriptor 中依赖的类型决定如何获取依赖对象
if (Optional.class == descriptor.getDependencyType()) {
// 依赖类型是 Optional 的情况
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
// 依赖类型是 ObjectFactory 的情况
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
// 依赖类型是 javax.inject.Provider 的情况
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 其他情况,从容器中获取所依赖的bean , 又分为 lazy依赖注入 和 非lazy依赖注入 两种情况
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 非lazy依赖注入的情况
result = doResolveDependency(descriptor, requestingBeanName,
autowiredBeanNames, typeConverter);
}
return result;
}
}
从上面的代码可见,整个依赖解析的过程如下 :
- 为依赖描述符设置参数名称发现器;
- 根据依赖描述符中携带的依赖类型的不同,执行不同的依赖对象获取分支。
在以上代码的if-else
分支中,最常用的分支应该是最后一个包含doResolveDependency
调用的分支了,这个分支是从容器中获取所依赖的bean
对象。接下来,我们对这一分支中的核心逻辑doResolveDependency
进行分析。
2.3 doResolveDependency(DependencyDescriptor,String,Set<String>,TypeConverter)
的实现
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames,
@Nullable TypeConverter typeConverter) throws BeansException {
// 此处涉及知识点 :
// 1. doResolveDependency 方法会被递归调用,从而导致 ConstructorResolver 被递归使用,
// 而 ConstructorResolver 使用 ThreadLocal 记录当前注入点,所以它在被递归调用时要首先保存
// 递归中上一层记录的注入点到 previousInjectionPoint , 在当前层 doResolveDependency 结束
// 时恢复 previousInjectionPoint 。如果没有该动作,则 ConstructorResolver 会出现错误行为。
// 2. DependencyDescriptor 继承自 InjectionPoint,
InjectionPoint previousInjectionPoint =
ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 某些 DependencyDescriptor 实现子类可能提供了快捷解析方式,所以这里先调用该方法尝试快捷解析,
// 而 DependencyDescriptor 类对该方法的缺省实现返回 null
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
// 快捷实现能够解析到依赖的情况,直接返回
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
// 看看有没有注解@Value提供的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// 有注解@Value提供值的情况
if (value instanceof String) {
// 现在 value 只是个字符串表达式,现在需要尝试对其求值,主要是使用具体值
// 替换其中的占位符
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
// 进行必要的类型转换并返回
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 针对依赖是 stream, 数组,Collection, Map 等类型的情况进行依赖bean的分析,
// 所返回的对象是 stream,数组,Collection, Map 这样类型的对象,其中的每个元素的类型
// 由依赖描述符中的类型决定,该方法调用中真正用到了 typeConverter 进行必要的类型转换
Object multipleBeans = resolveMultipleBeans(descriptor, beanName,
autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 针对依赖是单个 bean 依赖的情况进行依赖bean的分析
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 依赖被标记为 required, 但是却没有找打任何匹配的bean,
// 抛出异常 NoSuchBeanDefinitionException
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 依赖是单个 bean 依赖,但是却找到了多个依赖bean候选,
// 此时参考 @Primary,@Priority 等注解信息决定使用哪个bean作为最终要使用的依赖bean,
// 如果这些注解不存在,该步骤返回 null
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
// 参考@Primary,@Priority 等注解信息之后仍然分析不出合适的依赖bean,
// 此时看依赖是否被标记为 required 或者 不对应多个依赖bean,
// 如果是这些情况,使用依赖描述符自身的 resolveNotUnique 方法尝试解决,
// 缺省是抛出异常 NoUniqueBeanDefinitionException
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(),
matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 依赖是单个 bean 依赖,正好也只找到了一个候选依赖bean的情况
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
// 调用者提供了不为 null 的参数 autowiredBeanNames ,
// 表明需要向调用者通过此参数返回所找到的依赖的 bean 的名称
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// 其实是调用 beanFactory.getBean(autowiredBeanName) 触发获取所依赖的bean的实例
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
// 此时如果发现所找到的候选bean其实是一个特殊的bean NullBean,但依赖又被设定为 required,
// 这里仍旧抛出异常 NoSuchBeanDefinitionException
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
// 此时如果发现所找到的候选bean其实是一个特殊的bean NullBean,但依赖又没被设定为 required,
// 此时返回 null
result = null;
}
// 类型检查,如果类型不匹配抛出异常 BeanNotOfRequiredTypeException
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type,
instanceCandidate.getClass());
}
// 返回最终确定要是用的依赖bean
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}