可以看出,解析待注入字段或参数主要由 org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set<java.lang.String>, org.springframework.beans.TypeConverter)
和 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanByName
两种方法完成注入值解析, 本文将从源码角度分析 Spring 是如何解析?
一、Type-driven
在使用 @Autowired
注解或者 @Resource
注解在某些情况下,Spring 会将待解析字段或参数封装成 DependencyDescriptor
调用第一种解析方法,看下该方法源码,
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
// ...
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 待注入变量类型为Optional
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 待注入变量类型为ObjectFactory|ObjectProvider, 延迟注入
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// 待注入变量类型为javax.inject.Provider类型, 延迟注入
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// @Lazy延迟注入
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 实际依赖解析
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
/** Create an {@link Optional} wrapper for the specified dependency. */
private Optional<?> createOptionalDependency(
DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {
DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
@Override
public boolean isRequired() {
return false;
}
@Override
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :
super.resolveCandidate(beanName, requiredType, beanFactory));
}
};
// 实际解析
Object result = doResolveDependency(descriptorToUse, beanName, null, null);
return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
}
// ...
}
1. 延迟注入
这里主要根据待注入变量类型,处理依赖延迟注入情况,
-
Optional
, 立即解析,并将解析结果包装为Optional
; -
ObjectFactory
|ObjectProvider
,返回实现类DependencyObjectProvider
对象,并将依赖解析逻辑封装在其获取值相关 API 中,如org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#getObject()
,org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#stream
等,这样,在调用这些 API 获取实际值时,才发生依赖解析; -
javax.inject.Provider
,原理同上,实现方式不同,该类为 Jsr330 类,非 Spring 原生类; - 待注入变量被
@Lazy
注解,为该变量创建代理,在调用该变量任意方法时才调用org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
解析依赖值,然后调用目标对象相关方法,参考org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
;
2. 依赖解析
如果非以上情形,则需要调用 org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法立即解析待注入变量值,
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 处理缓存
// AutowiredAnnotationBeanPostProcessor在满足条件情况下将待注入变量解析bean名称缓存到ShortcutDependencyDescriptor
// prototype bean再次依赖注入时, 便可根据bean name解析bean实例
// 参考 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType(); // 待注入变量类型
// 计算@Value注解value属性,
// 例如, 如果待注入变量有@Value("${server.port}")注解, 则value值为"${server.port}"
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 解析"${}"占位符
// 最终由org.springframework.core.env.PropertyResolver#resolvePlaceholders处理
// 参考
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd); // 计算SpEL表达式
}
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()));
}
}
// 当待注入变量类行为 Array | Collection | Map 或者ObjectProvider调用流相关方法或者依赖值时, 此方法生效
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 找出所有和type即待注入变量类型相同候选bean, bean name => bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果此变量必须(@Autowired注解required属性为tru), 但不存在候选bean, 则抛异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// bean @Primary 注解,优先级,bean名称是否与待注入变量名称相同等条件筛选出唯一一个
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
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 {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// 根据bean名称最终调用org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法获取bean实例
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
解析待注入变量逻辑大致分如下几步,
- 调用
org.springframework.beans.factory.config.DependencyDescriptor#resolveShortcut
以快捷方式解析,对该方法提供实现只有ShortcutDependencyDescriptor
。可以看出org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
根据类型解析比较耗时,需要找出所有类型匹配 bean,再根据一些条件筛选,所以org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue
等函数中,如果满足条件,则其将解析完成的 bean 名称以及表示待注入变量的DependencyDescriptor
封装为ShortcutDependencyDescriptor
,当 prototype bean再次依赖注入时,便可直接通过 bean 名称解析; - 处理
@Value
占位符,其中又包括解析${}
占位符以及#{}
SpEL 表达式,类型转换等; - 调用
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveMultipleBeans
处理待注入变量为复合类型,包括Array
|Collection
|Map
或者ObjectProvider
,复合类型候选 bean 有多个时直接组装返回; - 通过
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
,首先找到所有和待注入变量类型匹配 bean,然后再根据 beanautowireCandidate
属性,@Qualifier
注解等条件筛选出候选 bean; - 如果候选 bean 存在多个,则通过
org.springframework.beans.factory.support.DefaultListableBeanFactory#determineAutowireCandidate
函数根据 bean@Primary
注解,优先级,是否与待注入变量名称相同等条件筛选出唯一一个;
3. 查找候选 bean
其中比较核心代码在函数 org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
查找所有候选 bean,看下源码,
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 从当前容器及其祖先容器中查找type为requiredType即待注入变量实际类型的bean名称
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
// resolvableDependencies一些特殊bean无法从IOC容器中获取, 需要直接判断类型是否匹配
// 比如, IOC容器本身, org.springframework.beans.factory.BeanFactory
// 应用上下文,org.springframework.context.ApplicationContext 等
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
// isSelfReference 判断是否将bean注入到自己字段或者方法参数中
// isAutowireCandidate 判断bean是否符合条件
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 将candidate Calss或其实例添加到结果result中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
// 后备
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
// 处理注入待注入变量为自身所属bean
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
α. 候选 bean 筛选
从以上源码可以看出为什么这节标题为 “Type-driven” 类型驱动,在查找候选 bean 时,Spring 首先将容器中所有和待注入变量类型相符所有 bean 找到, 然后再调用 org.springframework.beans.factory.support.DefaultListableBeanFactory#isAutowireCandidate(java.lang.String, org.springframework.beans.factory.config.DependencyDescriptor)
筛选符合条件 bean,该方法最终由 org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isAutowireCandidate
完成,
public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {
// ...
// 判断bdHolder是否能注入到待注入变量descriptor
@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
// 使用@Bean在Configuration中注入bean时, 可指定autowireCandidate为false
// 表示该bean不会被注入到其他bean属性或方法参数中,在筛选候选bean时, 会忽略掉这些bean
// 例如, @Bean(autowireCandidate = false)
// 另外, 这个方法中还会检测泛型是否匹配
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
if (match) {
// descriptor.getAnnotations()取值如下
// 如果待注入变量为字段, 则取该字段所有注解
// 如果待注入变量为方法参数, 则取方法参数所有注解
// checkQualifiers 主要根据@Qualifier参数筛选
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
// Set方法注入, 还要校验方法参数
if (method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
}
return match;
}
// ...
}
β. 根据限定符注解筛选
以上方法重中之重在 org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#checkQualifiers
检查 @Qualifier
注解, @Qualifier
注解可以限定注入 bean,
// annotationsToSearch =》 需要注入变量标注的所有注解
// bdHolder =》 待注入BeanDefinition
protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
if (ObjectUtils.isEmpty(annotationsToSearch)) {
return true;
}
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
for (Annotation annotation : annotationsToSearch) {
Class<? extends Annotation> type = annotation.annotationType();
boolean checkMeta = true;
boolean fallbackToMeta = false;
// 判断是否是限定符注解, 一下两种情况满足条件
// 1. @Qualifier本身
// 2. 被@Qualifier注解的注解, 例如, @LoadBalanced
// @Qualifier
// public @interface LoadBalanced {
// }
if (isQualifier(type)) {
if (!checkQualifier(bdHolder, annotation, typeConverter)) {
// fallbackToMeta 默认false, 只有不匹配才会被赋值为true
// 所以, fallbackToMeta=true 表示有限定符注解, 但是没有匹配成功
fallbackToMeta = true;
}
else {
checkMeta = false; // 匹配成功, 不需要匹配元数据
}
}
// checkMeta 默认为true, 没有限定符注解(isQualifier(type)返回false)或限定符注解没有匹配成功才会走到该分支
if (checkMeta) {
boolean foundMeta = false;
for (Annotation metaAnn : type.getAnnotations()) {
Class<? extends Annotation> metaType = metaAnn.annotationType();
if (isQualifier(metaType)) {
foundMeta = true;
// Only accept fallback match if @Qualifier annotation has a value...
// Otherwise it is just a marker for a custom qualifier annotation.
// 详细解释看后文
if ((fallbackToMeta && ObjectUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
!checkQualifier(bdHolder, metaAnn, typeConverter)) {
return false;
}
}
}
// 有限定符注解,没有匹配成功, 并且在元数据中没有找到限定符, 匹配失败
if (fallbackToMeta && !foundMeta) {
return false;
}
}
}
return true; // 所有限定符注解匹配成功才算成功匹配
}
源码大致意思已经注释在源码中,首先解释下参数, annotationsToSearch
,表示被注入变量所有注解,比如如下代码,
@Component
public class B {
@Autowired
@Qualifier
private A a;
}
那么在注入字段 A a
时,annotationsToSearch
数组中包含 @Qualifier
和 @Autowired
两个元素。bdHolder
表示 Spring IOC 容器中类型为 A 的 BeanDefinition
。
这里检查 bdHolder
@Qualifier
限定符注解能否和 A a
能否匹配。
方法 org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#isQualifier
用于判断注解是否为“限定符注解”,注意一定要记住这个名词 ——“限定符注解”,
protected boolean isQualifier(Class<? extends Annotation> annotationType) {
for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
return true;
}
}
return false;
}
从源码可以看出如下两种情况视为限定符注解,
-
@Qualifier
注解本身,称为第一种形式; - 注解被
@Qualifier
注解,例如@LoadBalanced
,称为第二种形式;
以上源码执行大致步骤如下,
- 先判断限定符注解能否直接匹配;
- 如果限定符注解能直接匹配(
checkMeta = false
),则不需要检查其元数据。如果注解非限定符注解(默认checkMeta = true
)或者限定符注解注解匹配失败(fallbackToMeta = true
,默认checkMeta = true
)则需要进入匹配元数据中限定符注解能否匹配; - 循环检查注解元数据中限定符注解能否匹配,这里分两种情况 —— 如果该注解本身为限定符注解例如
@Qualifier
|@LoadBalanced
…,只是没有匹配成功,那么只有@LoadBalanced
这种被@Qualifier
注解的限定符注解第二种形式元数据中才包含限定符注解(必定为@Qualifier
),此时fallbackToMeta = true
(本身没有匹配成功);如果注解本身非限定符注解,如果其元数据中出现限定符注解,那么该限定符注解只能是第二种形式,否则本身就是限定符注解; - 所有限定符注解匹配成功才算最终匹配成功;
这里主要看下匹配不成功情况,即返回 false
情况,
-
fallbackToMeta && !foundMeta
,注解为限定符注解且未匹配成功,且注解中未找到限定符注解,说明该注解为直接@Qualifier
注解且未匹配成功; -
fallbackToMeta && ObjectUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) || !checkQualifier(bdHolder, metaAnn, typeConverter)
,这里又分为两种情况,!checkQualifier(bdHolder, metaAnn, typeConverter)
元数据中的限定符注解匹配失败;另外一种情况比较难理解,但源码给了注释,解释如下,!fallbackToMeta && ObjectUtils.isEmpty(AnnotationUtils.getValue(metaAnn)))
,!fallbackToMeta
说明注解本身为限定符注解,那只能是第二种形式,其元数据metaAnn
必定为@Qualifier
,如果该注解被@Qualifier
注解时没有指定value
属性,那么@Qualifier
注解只是用来标识该注解为限定符注解,不需要匹配,原来匹配不成功那就是不成功,直接短路不需要匹配元数据。如果该注解被@Qualifier
注解时指定value
属性,那么再匹配元数据@Qualifier
。
例如,定义注解几个注解如下,
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier(value = "foo")
public @interface Genre {
String mark() default "";
}
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier()
public @interface Level2 {
String q();
}
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Level2(q="foo")
public @interface Level3 {}
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Level2(q="foo")
public @interface Level3Other {}
通过 Configuration 向 Spring IOC 容器中注入如下几个 bean,
@Configuration
public class Config {
@Bean("b1")
@Genre(mark = "bar")
public B b() {
return new B();
}
@Bean("b2")
@Level3Other
public B b2() {
return new B();
}
@Bean("b3")
@Qualifier(value = "foo")
public B b3() {
return new B();
}
@Bean("b4")
@Genre
public B b4() {
return new B();
}
}
bean A 中包含需要依赖注入字段 b
和 b1
,
@Component
public class A implements InitializingBean {
// b2
// @Level3Other和@Level3虽然非限定符注解, 但其都被限定符注解@Level2(q="foo")注解, 且属性q相同能匹配
@Autowired
@Level3
private Map<String, B> b;
// b1, b3, b4
// b1, 虽然直接限定符注解@Genre不能匹配(属性mark不同,分别为"foo"和"bar"),
// 但@Genre被@Qualifier注解时指定了Value @Qualifier(value = "foo"),所以后备匹配元数据@Qualifier也能匹配成功
// b3, 同b1, b3未被@Genre注解, 所以@Genre注解必定匹配失败, 元数据@Qualifier能匹配成功
// b4, 直接限定符注解@Genre能匹配成功
@Autowired
@Genre(mark = "foo")
private Map<String, B> b1;
@Override
public void afterPropertiesSet() throws Exception {
// b2
b.keySet().forEach(System.err::println);
System.err.println("=================");
// b1
// b3
// b4
b1.keySet().forEach(System.err::println);
}
}
γ. 限定符注解筛选原理
再来看下最后一个重要方法 —— org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#checkQualifier
,该方法判断 BeanDefinition
能否匹配限定符注解 annotation
,
protected boolean checkQualifier(
BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {
Class<? extends Annotation> type = annotation.annotationType();
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
// 可以在BeanDefinition指定该属性
// 详细参见解释一
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
if (qualifier == null) {
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
}
// qualifier不存在情况下, 匹配候选bean限定符注解
if (qualifier == null) {
// targetAnnotation表示候选bean中类型为type的限定符注解
// 词方法是从BeanDefinition标签里拿这个类型的注解声明,非XML配置此处targetAnnotation为null
// First, check annotation on qualified element, if any
Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type);
// Then, check annotation on factory method, if applicable
if (targetAnnotation == null) {
// 通过Configuration @Bean方法注入, 则从方法注解中获取, 如上注入bean b
targetAnnotation = getFactoryMethodAnnotation(bd, type);
}
if (targetAnnotation == null) {
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
if (dbd != null) {
// 从DecoratedDefinition的FactoryMethodAnnotation中获取
targetAnnotation = getFactoryMethodAnnotation(dbd, type);
}
}
if (targetAnnotation == null) {
// Look for matching annotation on the target class
if (getBeanFactory() != null) {
try {
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
if (beanType != null) {
// 从bean Class中获取
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Not the usual case - simply forget about the type check...
}
}
if (targetAnnotation == null && bd.hasBeanClass()) {
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(bd.getBeanClass()), type);
}
}
// 这里equals方法匹配两个注解中所有属性相同
// 详细参见解释二 java.lang.annotation.Annotation#equals
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
return true;
}
}
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (attributes.isEmpty() && qualifier == null) {
// If no attributes, the qualifier must be present
return false;
}
// 匹配限定符注解中所有属性
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String attributeName = entry.getKey(); // 属性名称
Object expectedValue = entry.getValue(); // 属性期望值, 即待注入变量该属性值
Object actualValue = null; // 属性期望值
// Check qualifier first
if (qualifier != null) {
actualValue = qualifier.getAttribute(attributeName);
}
if (actualValue == null) {
// Fall back on bean definition attribute
actualValue = bd.getAttribute(attributeName);
}
// 限定符注解value属性可以匹配bean名称
// 这也是最常见使用方式 —— 直接在@Qualifier直接value属性中指定候选bean名称
// 例如 @Qualifier(value = "foo"), 表示需要注入名称为foo的bean
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
// Fall back on bean name (or alias) match
continue;
}
if (actualValue == null && qualifier != null) {
// Fall back on default, but only if the qualifier is present
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
}
if (actualValue != null) {
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
}
if (!expectedValue.equals(actualValue)) {
return false;
}
}
return true;
}
解释一,AutowireCandidateQualifier
该类可以使用非注解方式指定可以匹配的限定符注解,例如,存在如下限定符注解,
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier()
public @interface CustomizedQualifier {
String property() default "";
}
向Spring IOC 容器注册如下 bean b,
@Configuration
public class Config {
@Bean("b")
public B b(){ return new B();}
}
bean a 中字段 b 使用限定符注解 CustomizedQualifier
依赖 bean b 时将依赖不到,因为 bean b 没有使用该限定符注解,故不能匹配成功,
@Component
public class A implements InitializingBean {
// n=null, 容器中没有能匹配 @CustomizedQualifier(property = "foo") 且类型为 B 的 bean
@Autowired(required = false)
@CustomizedQualifier(property = "foo")
private Map<String, B> b;
@Override
public void afterPropertiesSet() throws Exception {
// java.lang.NullPointerException
b.keySet().forEach(System.err::println);
}
}
这时,通过 org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory
修改 bean b BeanDefinition —— 向其添加一个表示 @CustomizedQualifier
的 AutowireCandidateQualifier
,如下
@Component
public class QualifierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition b = beanFactory.getBeanDefinition("b");
if (b instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) b;
// 新建表示CustomizedQualifier的AutowireCandidateQualifier
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(CustomizedQualifier.class);
// 限定符注解属性也要匹配成功
qualifier.setAttribute("property", "foo");
abd.addQualifier(qualifier);
}
}
}
此时bean a 中字段 b 就能成功依赖到 bean b。
解释二 java.lang.annotation.Annotation#equals
对于注解, Java 会为其生成代理 AnnotationInvocationHandler
,在 sun.reflect.annotation.AnnotationInvocationHandler#invoke
中会拦截 equals()
方法,
public Object invoke(Object var1, Method var2, Object[] var3) {
String var4 = var2.getName();
Class[] var5 = var2.getParameterTypes();
if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) { // 拦截equals()方法
return this.equalsImpl(var3[0]);
} else if (var5.length != 0) {
throw new AssertionError("Too many parameters for an annotation method");
}
// ...
}
看下 this.equalsImpl()
对拦截的 equals()
方法做了什么,
private Boolean equalsImpl(Object var1) {
if(var1 == this) { //本身和本身equals必定为true
return true;
} else if (!this.type.isInstance(var1)) { // 类型不匹配
return false;
} else {
// 注解中属性通过定义方法表示, 例如, String value() default ""; 表示value属性
// 获取所有成员方法, 相当于获取所有属性
Method[] var2 = this.getMemberMethods();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Method var5 = var2[var4];
String var6 = var5.getName(); // 属性名称
Object var7 = this.memberValues.get(var6); // 本省该属性值
Object var8 = null;
AnnotationInvocationHandler var9 = this.asOneOfUs(var1);
if (var9 != null) {
var8 = var9.memberValues.get(var6);
} else {
try {
var8 = var5.invoke(var1); // 比较对象该属性值
} catch (InvocationTargetException var11) {
return false;
} catch (IllegalAccessException var12) {
throw new AssertionError(var12);
}
}
// 如果var7不为数组, 则直接调用该对象equals()方法比较
// 否则, 调用Arrays相关数组比较方法比较两个数组是否相等
if (!memberValueEquals(var7, var8)) { // 判断该属性值是否相等
return false;
}
}
return true; // 所有属性值相等才算两个注解equals()为true
}
}
从上面源码可以看出 —— java.lang.annotation.Annotation#equals
方法处理逻辑是,该注解所有属性 equals()
方法返回 true
,结果才为 true
。
例如定义注解,
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Eq {
String name() default "";
String key() default "";
String value() default "";
}
类 A
,B
,C
分别有该注解,
@Eq(name = "a", key = "keyA", value = "q")
public class B { }
@Eq(name = "a", key = "keyA", value = "1q")
public class C { }
@Eq(name = "a", key = "keyA", value = "1q")
public class A {
public static void main(String[] args) {
Eq annotationA = A.class.getAnnotation(Eq.class);
Eq annotationB = B.class.getAnnotation(Eq.class);
Eq annotationC = C.class.getAnnotation(Eq.class);
// false, 属性value不匹配
System.err.println(annotationA.equals(annotationB));
// true, 所有属性均匹配
System.err.println(annotationA.equals(annotationC));
}
}
回到 checkQualifier
从函数,看下该函数如何认定一个 BeanDefinition 能匹配待注入变量限定符注解,
- 首先根据限定符注解类型全限定名和短名称从 BeanDefinition 中获取
AutowireCandidateQualifier
; - 如果步骤一未获取到
AutowireCandidateQualifier
,则尝试获取该类型限定符注解并和annotation
匹配一波(需要两个注解所有属性equals()
方法返回true
,才算匹配成功,详细参考以上解释二),匹配成功,提前结束。获取同类型限定符注解方式为,如果该 bean 通过 Configuration 配置类@Bean
方法注入,则从该方法注解中获取,获取失败,则从该 bean Class 文件中中获取。这里有一个小问题 —— 如果@Bean
方法和 Class 文件中都有该限定符注解呢?从源码可以看出最终以@Bean
方法为准,Class 文件中并不会生效; - 匹配限定符注解中所有属性,这些属性值可能来源于,
AutowireCandidateQualifier
| BeanDefinition | bean 名称(属性value
在前两种来源获取不到时才会取 bean 名称),默认值(AutowireCandidateQualifier
) 需存在; - 所有属性值匹配成功,返回
true
,有一个匹配失败则返回false
;
二、Name-driven
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanByName
根据名称解析依赖 bean 实现比较简单,因为每个 bean 对应唯一名称,不存在“筛选”过程;
@Override
public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
return getBean(name, descriptor.getDependencyType());
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
该方法最终会调用到的 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
,该方法比较经典,这里不打算继续书写。