在Spring启动流程中,创建的factoryBean是DefaultListableBeanFactory,其类图如下所示:
可以看到其直接父类是AbstractAutoireCapableBeanFactory,他主要负责完成Bean的自动装配和创建工作。 具体来说,AbstractAutowireCapableBeanFactory会完成以下工作:
- 根据Bean的定义信息创建Bean实例;
- 根据Bean的定义信息完成Bean的依赖注入;
- 根据Bean的定义信息完成Bean的初始化工作;
- 返回创建好的Bean实例。
其中,属性注入是AbstractAutowireCapableBeanFactory的核心功能之一。它会根据Bean的定义信息,自动将依赖的Bean注入到当前Bean中。具体来说,它会根据Bean的依赖关系,自动查找并创建依赖的Bean实例,并将其注入到当前Bean中。
除了属性注入,AbstractAutowireCapableBeanFactory还支持构造函数注入、工厂方法注入等多种注入方式,可以满足不同场景下的需求。
其核心方法AbstractAutowireCapableBeanFactory#populateBean,下面,我们看一下populateBean方法是怎么进行依赖注入的。它处理Spring的各种依赖注入:包括自动注入(名称注入和类型注入)、注解注入(@Autowired和@Value等)、手动注入等。
-
首先,判断是否需要进行属性注入。调用 ibp#postProcessAfterInstantiation
-
自动注入 :包括名称注入和类型注入。不推荐使用,只支持 XML 配置方式。
-
注解注入:处理 @Autowired 和 @Value 等注解,Spring 提供 ibp#postProcessProperties 可以调整 bean 实例。如 AutowiredAnnotationBeanPostProcessor 用于处理 @Autowired 和 @Value 注解。CommonAnnotationBeanPostProcessor 用于处理 @Resource 注解。
-
依赖检查:检查要注入的依赖是否已经完整。可以只检查简单类型(Java 原生类型、Enum、Class 等),也可以只检查对象类型。
-
手动注入:最基础的注入方式,实际上都委托给了 BeanWrapper 处理。
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 1. 判断是否需要进行属性注入:ibp#postProcessAfterInstantiation
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 2. 自动注入:包括名称注入和类型注入
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 2.1 自动根据名称注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 2.2 自动根据类型注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
// 3. 注解注入:后置处理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在这处理的。
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 4. 依赖检查,循环依赖...
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 5. 手动依赖注入
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
这里重点讲解AutowiredAnnotationBeanPostProcessor为代表的注解注入方式。其会调用到Spring进行依赖查找的核心API: beanFactory#resolveDependency,其本质是根据类型查找依赖,调用beanFactory#beanNamesForType方法根据类型查找依赖名称。他解决了以下四个场景:
-
Optional:JDK8 提供了 API。主要是将依赖设置非强制依赖,即 descriptor.required=false。
-
延迟依赖注入支持:ObjectFactory、ObjectProvider、javax.inject.Provider
-
另一种延迟注入的支持 - @Lazy 属性。
-
根据类型查找依赖 - doResolveDependency。
java
@Override
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ParameterNameDiscovery用于解析方法参数名称
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 1. Optional<T>
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
// 2. ObjectFactory<T>、ObjectProvider<T>
} else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
// 3. javax.inject.Provider<T>
} else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
} else {
// 4. @Lazy
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
// 5. 正常情况
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
最底层都会调用beanFactory#doResolveDependency方法,其封装了依赖查找的各种情况。
-
快速查找: @Autowired 注解处理场景。AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注解时,如果注入的对象只有一个,会将该 bean 对应的名称缓存起来,下次直接通过名称查找会快很多。
-
注入指定值:@Value 注解处理场景。QualifierAnnotationAutowireCandidateResolver 处理 @Value 注解时,会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换,这也是一般的处理过程,BeanDefinitionValueResolver 处理 String 对象也是这个过程。
-
集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。
-
单个依赖查询:先调用 findAutowireCandidates 查找所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority -> ③方法名称或字段名称。
java
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 1. 快速查找,根据名称查找。AutowiredAnnotationBeanPostProcessor用到
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value会用到
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 2.1 占位符解析
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 2.2 Spring EL 表达式
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 2.3 类型转换
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
} catch (UnsupportedOperationException ex) {
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 3. 集合依赖,如 Array、List、Set、Map。内部查找依赖也是使用findAutowireCandidates
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 4. 单个依赖查询
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 4.1 没有查找到依赖,判断descriptor.require
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 4.2 有多个,如何过滤
if (matchingBeans.size() > 1) {
// 4.2.1 @Primary -> @Priority -> 方法名称或字段名称匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
// 4.2.2 根据是否必须,抛出异常。注意这里如果是集合处理,则返回null
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
} else {
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();
}
// 4.3 到了这,说明有且仅有命中一个
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 4.4 实际上调用 getBean(autowiredBeanName, type)。但什么情况下会出现这种场景?
if (instanceCandidate instanceof Class) {
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);
}
}
这里重点看下看下第四种单个依赖的查询,集合依赖与其异曲同工:
-
查找容器中所有可用依赖:findAutowireCandidates 方法根据类型查找依赖。
-
如何有多个依赖怎么处理?其实 Spring 有一套通用的流程,先按 @Primary 查找,再按 @Priority,最后按方法名称或字段名称查找,直到只有一个 bean 为止。相关的匹配规则见 determineAutowireCandidate 方法。
-
此时只有一个依赖,从容器获取真实的 bean。descriptor.resolveCandidate 方法根据名称 autowiredBeanName 实例化对象。
从 findAutowireCandidates 方法,我们可以看到 Spring IoC 依赖注入的来源:
-
先查找 Spring IoC 内部依赖 resolvableDependencies。在 AbstractApplicationContext#prepareBeanFactory 方法中默认设置了如下内部依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。
-
在父子容器进行类型查找:查找类型匹配的 beanNames,beanFactory#beanNamesForType 方法根据类型查找是,先匹配单例实例类型(包括 Spring 托管 Bean),再匹配 BeanDefinition 的类型。从这一步,我们可以看到 Spring 依赖注入的另外两个来源:一是 Spring 托管的外部 Bean,二是 Spring BeanDefinition。
java
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 1. Spring IoC 内部依赖 resolvableDependencies
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;
}
}
}
// 2. 类型查找:本质上递归调用beanFactory#beanNamesForType。先匹配实例类型,再匹配bd。
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
for (String candidate : candidateNames) {
// 2.1 isSelfReference说明beanName和candidate本质是同一个对象
// isAutowireCandidate进一步匹配bd.autowireCandidate、泛型、@@Qualifier等进行过滤
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 2.2 添加到候选对象中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 3. 补偿机制:如果依赖查找无法匹配,怎么办?包含泛型补偿和自身引用补偿两种。
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// 3.1 fallbackDescriptor: 泛型补偿,实际上是允许注入对象类型的泛型存在无法解析的情况
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
// 3.2 补偿1:不允许自称依赖,但如果是集合依赖,需要过滤非@Qualifier对象。什么场景?
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 3.3 补偿2:允许自称依赖,但如果是集合依赖,注入的集合依赖中需要过滤自己
if (result.isEmpty() && !multiple) {
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
findAutowireCandidates 大致可以分为三步:先查找内部依赖,再根据类型查找,最后没有可注入的依赖则进行补偿。
-
查找内部依赖:Spring IoC 容器本身相关依赖,这部分内容是用户而言是透明的,也不用感知。resolvableDependencies 集合中注册如 BeanFactory、ApplicationContext 、ResourceLoader、ApplicationEventPublisher 等。
-
根据类型查找:包括 ①外部托管 Bean ②注册 BeanDefinition。类型查找调用 beanFactory#beanNamesForType 方法。
-
自身引用:isSelfReference 方法判断 beanName 和 candidate 是否是同一个对象,包括两种情况:一是名称完全相同,二是 candidate 对应的工厂对象创建了 beanName。
-
是否可以注入:底层实际调用 resolver.isAutowireCandidate 方法进行过滤,包含三重规则:①bd.autowireCandidate=true -> ②泛型匹配 -> ③@Qualifier。下面会详细介绍这个方法。
-
-
补偿机制:如果依赖查找无法匹配,怎么办?Spring 提供了两种补偿机制:一是泛型补偿,允许注入对象对象的泛型无法解析,二是自身引用补偿,对这两种机制使用如下:
-
先使用泛型补偿,不允许自身引用:即 fallbackDescriptor。此时如果是集合依赖,对象必须是 @Qualifier 类型。
-
允许泛型补偿和自身引用补偿:但如果是集合依赖,必须过滤自己本身,即 beanName.equals(candidate) 必须剔除。
-