前言
通过上一篇spring 源码解析之 createBeanInstance已经了解了 spring 如何创建 bean 实例的,创建完实例之后,接下来就是属性注入的问题了。本篇文章就是解释 spring 如何进行属性注入的。开卷!
源码解析
populateBean概述
populateBean
方法主要负责对@Autowired、@Resource、@Value
等注解标注的属性进行填充
,一些普通的成员变量则通过反射或者构造函数、set 方法等注入
。- 根据bean定义从给定的
BeanWrapper
中获取属性值,并在设置属性之前允许任何InstantiationAwareBeanPostProcessors
修改bean的状态(这个是后置处理器内容,后续详细讲)。- 根据
bean定义的配置
,可以进行自动装配
类型(ByName或ByType)的属性值设置,并且可以进行属性值的后处理。- 最后,将属性值应用于bean实例中。直接看源码。
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
// 如果beanWrapper为空,说明bean实例为null,需要跳过property值的设置
// 但是如果beanWrapper为空而且mbd.hasPropertyValues()为true,说明bean实例为null,bean定义中存在property值,需要抛出异常
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// 如果Bean是记录类型,那么Spring将跳过属性填充阶段,因为记录类型的属性是不可变的,无法进行属性注入
if (bw.getWrappedClass().isRecord()) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
}
else {
// Skip property population phase for records since they are immutable.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 在设置属性之前,让任何InstantiationAwareBeanPostProcessors都有机会修改bean的状态。例如,这可以用于支持现场注入的样式。
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
// 属性填充值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 自动装配类型 byName byType
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根据pvs 封装属性值
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 添加属性值,根据byName
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 添加属性值,根据byType
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 此工厂是否持有InstantiationAwareBeanPostProcessor后置处理器
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍历后置处理器,如果返回非空的PropertyValues,将pvs更新为返回的PropertyValues
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 将属性应用到 bean 中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
-
检查传入的
BeanWrapper
对象是否为空,如果为空且bean定义中有属性值,则抛出异常,表示不能对null实例应用属性值。若两者都为空,则直接跳过属性填充阶段。 -
如果
bean是Java记录类型(Record)
,由于其属性不可变(有点类似于 final),因此也跳过属性填充阶段。若记录类型存在属性值,则同样抛出异常。 -
在设置属性之前,调用注册在容器中的所有
InstantiationAwareBeanPostProcessor
,允许它们有机会通过postProcessAfterInstantiation
方法修改bean实例的状态,这也相当于 AOP 中的后置处理器进行方法增强。 -
根据bean定义中的自动装配模式(
resolvedAutowireMode
)决定如何填充属性值:AUTOWIRE_BY_NAME
:根据bean名称自动注入属性。AUTOWIRE_BY_TYPE
:根据类型自动注入属性。
-
再次遍历
InstantiationAwareBeanPostProcessor
,让它们有机会通过postProcessProperties
方法进一步修改或替换
已填充的属性值。 -
如果
bean
定义启用了依赖检查功能,那么会进行依赖项检查以确保注入的属性值满足依赖关系。 -
最后,使用最终确定的属性值集合(
PropertyValues
)调用applyPropertyValues
方法,将这些属性值实际地应用到bean实例上
。 -
总结来说,这个函数实现了Spring框架在创建bean实例后的初始化阶段,处理
自动装配
和属性值注入
等核心功能,并允许自定义扩展点对这一过程进行干预和定制。
举个例子解释一下上面涉及到几个参数的意思
java
public class Person {
private String name;
@Autowired
private Address address;
// getters and setters...
}
public class Address {
private String street;
private String city;
// getters and setters...
}
@Configuration
public class AppConfig {
@Bean
public Address address() {
Address address = new Address();
address.setStreet("123 Main St");
address.setCity("Springfield");
return address;
}
@Bean
public Person person(Address address) {
Person person = new Person();
person.setName("John Doe");
// 由于使用了@Autowired注解,此处可以不手动设置address
return person;
}
}
解释上面的代码
-
在Spring容器初始化Person bean时,会调用populateBean进行属性注入。
-
mbd(RootBeanDefinition)
包含了对Person bean的所有定义信息,包括属性值和自动装配模式。 -
bw(BeanWrapper)
封装了Person对象实例。 -
在populateBean方法执行过程中
:- 首先检查bw是否为空,如果不为空则继续处理。
- 由于配置中没有指定Person的address属性值,但设置了
自动装配
模式(默认或显式设置为AUTOWIRE_BY_TYPE),所以会根据类型找到并注入匹配的Address bean到Person的address属性上。 - 如果存在任何
InstantiationAwareBeanPostProcessor
,则会在注入属性前和后分别调用它们的方法进行处理。 最终,将所有确定好的属性值(包括直接赋值的name和通过自动装配获取的address)封装在PropertyValues(pvs)中。
- 调用
applyPropertyValues
方法,将pvs中的属性值应用到Person
实例中,即设置其name属性为"John Doe",并将从address bean中获取的地址信息注入到Person的address属性中。
populateBean 详细解析
autowireByName
此函数实现了
按名称自动装配
策略,即如果一个Bean的属性名与另一个已存在的Bean名相匹配,则会将这个Bean实例添加到MutablePropertyValues
待注入的属性值
java
/**
* Fill in any missing property values with references to
* other beans in this factory if autowire is set to "byName".
* @param beanName the name of the bean we're wiring up.
* Useful for debugging messages; not used functionally.
* @param mbd 存着 bean 定义的信息
* @param bw 存着 JavaBean 类信息
* @param pvs 需要填充的属性值
*/
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 找出当前Bean中需要依赖注入且尚未填充的属性名称数组propertyNames
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
// 检查缓存是否有当前 bean
// 如果到了依赖注入的时候,此时所依赖的 bean 肯定都已经实例化完成了
if (containsBean(propertyName)) {
// 递归获取 bean 实例
Object bean = getBean(propertyName);
// 添加到传入的MutablePropertyValues参数pvs中
pvs.add(propertyName, bean);
// 记录依赖关系,将当前Bean(beanName)注册为依赖于新注入的Bean(propertyName)的Bean
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
-
函数首先调用
unsatisfiedNonSimpleProperties(mbd, bw)
来找出当前Bean中需要依赖注入且尚未填充的属性名称
数组propertyNames。 -
针对数组中的每个属性名称:
- 使用
containsBean(propertyName)
检查当前BeanFactory中是否存在与该属性名称相同的Bean。 - 如果存在,则通过
getBean(propertyName)
获取对应的Bean实例,并将其添加到传入的MutablePropertyValues
参数pvs
中,即将该Bean实例注入到原Bean的对应属性上
。 - 调用
registerDependentBean(propertyName, beanName)
记录依赖关系,将当前Bean(beanName)注册为依赖于新注入的Bean(propertyName)的Bean。 - 若在BeanFactory中找不到与属性名称匹配的Bean,则同样根据日志级别输出未找到匹配Bean的信息,此时不进行自动装配。
- 使用
autowireByType
跟
autowireByName
类型,不同的是此方法按类型自动注入(autowire by type)
的行为。它会根据Bean的类型在Bean工厂中查找依赖的Bean,并将其注入到需要依赖注入的属性中。
java
/**
* Abstract method defining "autowire by type" (bean properties by type) behavior.
* <p>This is like PicoContainer default, in which there must be exactly one bean
* of the property type in the bean factory. This makes bean factories simple to
* configure for small namespaces, but doesn't work as well as standard Spring
* behavior for bigger applications.
* @param beanName 待注入依赖项的目标Bean的名称
* @param mbd 合并后的Bean定义,用于更新通过自动注入的信息
* @param bw 一个BeanWrapper对象,它封装了目标Bean,提供了获取Bean属性信息的能力
* @param pvs MutablePropertyValues对象,用于存储注册的已连接对象(即被注入的Bean)
*/
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取类型转换器
TypeConverter converter = getCustomTypeConverter();
// bw是BeanWrapper类型的对象,它内部已经包含了基本类型和常见对象类型的转换逻辑,可以处理大部分类型转换的需求
if (converter == null) {
converter = bw;
}
// 获取需要依赖注入的属性名
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
Set<String> autowiredBeanNames = new LinkedHashSet<>(propertyNames.length * 2);
for (String propertyName : propertyNames) {
try {
// 获取属性描述符 以获得其类型和访问方法(getter/setter)
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is an unsatisfied, non-simple property.
// 检查属性类型是否为Object类,由于按类型注入Object没有实际意义,所以跳过这类属性
if (Object.class != pd.getPropertyType()) {
// 获取set方法参数
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
// 创建一个DependencyDescriptor来表示当前属性的依赖关系,其中包含了相关的方法参数信息以及是否允许优先初始化的标志
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析指定beanName 的属性所匹配的值,并把解析到的属性名存储在 autowiredBeanNames 中
// 当属性存在多个封装bean时,如 @Autowired List<Bean> beans,会找到所有的匹配Bean 类型的bean并将其注入。
// 这里的返回值是真正的需要注入的属性, autowiredBeanNames 是需要注入的属性(可能是集合)的names
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 添加到待注入的bean列表中
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 注册依赖关系。操作 dependentBeanMap 和 dependenciesForBeanMap 集合
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
-
获取自定义的类型转换器,如果不存在,则使用传入的
BeanWrapper
作为默认的类型转换器。这里可以使用 bw 作为转换器的原因是因为BeanWrapper类型的对象它内部已经包含了基本类型和常见对象类型的转换逻辑,可以处理大部分类型转换的需求
-
unsatisfiedNonSimpleProperties
确定目标Bean
中未满足且非简单的属性名,这些属性需要进行自动注入。下面会详细讲 -
遍历每个未满足的属性:
- 获取当前属性的描述符
(PropertyDescriptor)
以获得其类型和访问方法(getter/setter)
。 - 检查属性类型是否为Object类,由于按类型注入Object没有实际意义,所以跳过这类属性。
- 创建一个
DependencyDescriptor
来表示当前属性的依赖关系,其中包含了相关的方法参数信息以及是否允许优先初始化的标志。 - 使用
resolveDependency
方法查找与当前属性类型相匹配的Bean实例
,并将匹配到的Bean添加到autowiredBeanNames
集合中。 - 如果找到了匹配的Bean实例,则将其注入到目标Bean的相应属性上,并将注入信息添加到pvs中。
- 将所有注入的
Bean名称记录在依赖关系映射中
,以便后续进行生命周期管理
等操作。 - 清空
autowiredBeanNames
集合,以便处理下一个属性。 - 在解析和注入过程中,如果遇到异常(如找不到匹配的依赖Bean),则抛出UnsatisfiedDependencyException,提供详细的错误信息。
- 获取当前属性的描述符
unsatisfiedNonSimpleProperties
从一个已创建的bean中找出所有未被设置且类型非简单的属性(即它们不是基本类型或字符串类型,可能是其他bean的引用
java
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
// 获取bean 的property 属性
PropertyValues pvs = mbd.getPropertyValues();
// 获取 bw 中的属性描述
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 存在 set 方法 && 属性不被排除 && 不存在在属性值中 && 不是简单类型
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
// 添加到结果集中
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
-
初始化一个
TreeSet类型的集合result
,用于存储满足条件的非简单属性名称。 -
从
mbd获取该bean的所有属性值
(PropertyValues pvs)。 -
通过
bw获取bean的所有属性描述符
(PropertyDescriptor[] pds)。 -
遍历每一个属性描述符pd:
- 检查pd是否有写入方法(即setter方法),这意味着属性是可以被外部设置的;
- 确定该属性是否被排除在依赖检查之外;
- 检查属性值集合pvs中是否包含该属性名称,若不包含则表示该属性尚未被设置,因为如果包含则是手动注入,不是自动装配了
- 使用
BeanUtils.isSimpleProperty(pd.getPropertyType())
判断该属性类型是否为简单类型,如int, String等,如果不是,则认为是复杂类型,可能是指向其他bean的引用; - 若以上条件都满足,则将该属性名称添加到结果集result中。
- 最后,使用StringUtils.toStringArray(result)将结果集合转换成字符串数组并返回。
resolveDependency
下面继续看
DefaultListableBeanFactory#resolveDependency
,用于解决依赖注入中依赖对象的解析。根据依赖对象的类型进行不同处理,包括处理可选依赖、依赖工厂、依赖提供者和一般类型依赖。如果依赖对象是懒加载的,会创建一个代理对象注入bean。最后返回解析后的依赖对象。
java
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 针对不同类型的不同处理
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 处理bean是否懒加载,如果懒加载,创建一个代理对象注入bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 针对一般类型的通用
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
这里我们主要关注最后面的,一般通用类型的依赖解析doResolveDependency
doResolveDependency
它的主要任务是根据给定的
DependencyDescriptor
参数解析并解决依赖关系,最终返回符合要求的对象实例。
java
/**
* 确实解决依赖关系
*
* @param descriptor 这个参数封装了依赖注入点的详细信息,可以是字段(Field),也可以是方法参数(MethodParameter)。它包含了一些关于依赖的信息,如依赖是否必须存在,依赖的类型等
* @param beanName bean名称
* @param autowiredBeanNames 这个参数是一个集合,用于收集所有自动装配的bean的名称。当Spring解析依赖并找到匹配的bean时,会将这些bean的名称添加到这个集合中
* @param typeConverter 型转换器
*/
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 设置当前注入点
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 尝试从缓存中获取
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 获取依赖的类型
Class<?> type = descriptor.getDependencyType();
// 取值@Value注解中的value属性中的值,这里取出的值是未经修改的值,即带有 ${} 标签的值。如果descriptor未被@Value标注,则返回null
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// 到这里说明属性被 @Value 注解修饰了,这里是解析 @Value 注解的逻辑
// 如果value不为null,
if (value instanceof String strValue) {
// 处理占位符如${},做占位符的替换(不解析SP EL表达式)
String resolvedValue = resolveEmbeddedValue(strValue);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析SP EL(如#{})
value = evaluateBeanDefinitionString(resolvedValue, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 类型转换,把解析出来的结果转成type类型
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。后面详解
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 调用查找所有类型为type的实例,存放在matchingBeans <beanName, bean> (在 resolveMultipleBeans 方法中也是核心也是调用该方法)。下面详解
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果没有找到,并且bean 并标注为 required = true, 则抛出NoSuchBeanDefinitionException异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果找到了不止一个匹配的bean,Spring 按照一定规则进行挑选
if (matchingBeans.size() > 1) {
// 按以下顺序,找到符合条件的就直接返回
// 1. 挑选出被标识为primary的bean
// 2. 挑选标识了@Priority,且先级级最高的bean。可以不标识,一旦标识,不允许同一优先级的存在
// 3. fallback,依赖的名称与matchingBeans中任意一Key匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 非集合类,找到了多个符合条件的Bean,抛出异常
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) {
// 将待装配的Bean名称放入autowiredBeanNames集合里
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// 这里又去调用 getBean 方法去获取bean
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
// 如果 result 是 NullBean类型,且 required = true,则抛出异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
// 类型校验,确保类型与解析出来的Bean实例能够匹配
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
-
设置当前注入点:使用
ConstructorResolver.setCurrentInjectionPoint()
记录当前正在处理的注入点信息。稍微解释一下
再简单来说,比如有 10 个依赖需要注入,这次注入第一个,那就记录我现在注入的是第一个相关的信息,然后第一个注入完之后,注入第二个的时候就不用判断第一个是否已经注入了,因为设置了切入点,直接从切入点往下继续注入第二个
-
尝试从缓存获取快捷方式:检查是否有之前已经计算过的快捷引用,如果存在则直接返回。
-
获取依赖类型,并尝试
解析@Value注解
:如果属性被@Value
注解修饰,则提取注解值,处理其中的占位符(如${...})
,然后进行SpEL表达式(如#{...})
的解析及类型转换,确保结果与依赖类型的匹配性。 这里稍微解释一下这三个方法。-
resolveEmbeddedValue
:这个方法主要是来读取如@Value("${my.property}")
这种注解的占位符,将配置文件的值读取出来进行替换
-
getMergedBeanDefinition
:获取合并后的Bean
定义对象(BeanDefinition),即包含了父级Bean定义以及其他任何影响该Bean的元数据信息。 -
evaluateBeanDefinitionString
:用于在给定的Bean定义上下文中评估一个字符串表达式,这通常涉及到对SpEL表达式的解析
与执行。例如xml<bean id="exampleBean" class="com.example.ExampleBean"> <property name="message" value="#{systemProperties['user.home']}/config/message.txt"/> </bean>
- 在这里,
#{systemProperties['user.home']}
是一个SpEL
表达式,它会在运行时动态计算得到系统的用户主目录。Spring容器在处理message
属性时,会调用evaluateBeanDefinitionString
方法来计算这个SpEL表达式,并将结果作为实际值注入到ExampleBean的message字段中
。
- 在这里,
-
-
处理集合类型(
Array、Collection、Map
)的依赖注入:调用resolveMultipleBeans()
方法来查找并注入多个符合条件的bean。 -
查找所有候选的bean:通过
findAutowireCandidates()
方法查找类型匹配的所有bean实例。 -
选择合适的bean:在找到多个候选bean时,按照优先级规则(
primary bean、@Priority注解排序等
)确定唯一的一个autowiredBeanName
及其对应的bean实例
。 -
如果是
可选依赖且未找到
匹配项或者找到多个但不符合单例条件
,则根据具体情况决定是否抛出异常或返回null。 -
类型检查:确保
选定的bean
实例可以被安全地赋值
给原始依赖类型。 -
更新
自动装配
的bean名称集合并返回结果:将实际装配的bean名
称添加到autowiredBeanNames
集合中,并返回已解决的依赖对象实例。 -
最后,在函数结束时恢复先前的注入点信息。
总之,这个函数实现了Spring框架核心的依赖注入逻辑,涵盖了单例、多例、注解驱动的值注入以及集合类型的依赖解析等多种场景。
resolveMultipleBeans
resolveMultipleBeans
主要用于处理Spring框架中的自动装配逻辑,针对不同的依赖类型
(如Stream、数组、集合或Map),它会查找符合条件的bean并进行相应的转换和排序,最终返回一个注入结果
java
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
// 获取依赖的类型
Class<?> type = descriptor.getDependencyType();
// 如果是 StreamDependencyDescriptor 类型,则返回流的形式
// 我在开发中未遇到过有这种类型的 bean
if (descriptor instanceof StreamDependencyDescriptor streamDependencyDescriptor) {
// 寻找并返回能够自动装配给定依赖类型的候选bean集合
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 将这些bean根据名称解析为对象,并过滤掉值为 NullBean 的bean
Stream<Object> stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(bean -> !(bean instanceof NullBean));
// 如果依赖需要排序,则按照自定义比较器对流进行排序,最后返回这个流对象
if (streamDependencyDescriptor.isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
// 数组类型
else if (type.isArray()) {
// 确定数组元素的具体类型
Class<?> componentType = type.getComponentType();
// 当前依赖项的实际或期望的类型
ResolvableType resolvableType = descriptor.getResolvableType();
Class<?> resolvedArrayType = resolvableType.resolve(type);
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
// 找到所有符合依赖项类型的所有 bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
// 将所有符合依赖项类型的bean放入 autowiredBeanNames 集合里
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
// 用TypeConverter将bean集合转换成指定集合类型
Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
// 集合元素数量大于1,按需进行排序
if (result instanceof Object[] array && array.length > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
Arrays.sort(array, comparator);
}
}
return result;
}
// 下面的几个跟数组类型的类似 就不多讲了
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List<?> list && list.size() > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
list.sort(comparator);
}
}
return result;
}
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
return null;
}
}
- 函数首先获取依赖描述符
descriptor
中表示的依赖类型。 - 若依赖类型是
StreamDependencyDescriptor
的实例,则通过findAutowireCandidates
方法找到所有匹配候选bean的集合。然后创建一个流,将这些bean
根据名称解析为对象,并过滤掉值为NullBean 的bean
。如果依赖需要排序,则按照自定义比较器对流进行排序,最后返回这个流对象。 - 若依赖类型是
数组
,函数确定数组元素的具体类型并查找相应类型的候选bean
。找到后,将bean名称添
加到autowiredBeanNames
中(如果非空)。然后使用TypeConverter
将候选bean集合转换为目标数组类型,并在满足条件时对数组元素进行排序
,最后返回转换后的数组。 - 若依赖类型是实现了
Collectio
n 接口的类且为接口类型,函数确定集合元素的实际类型并查找匹配的bea
n。同样添加bean名称至autowiredBeanNames,并用TypeConverter将bean集合转换成指定集合类型。若转换后的集合元素数量大于1,按需进行排序,最后返回转换后的集合。 - 若依赖类型是 Map 类型且键为字符串类型,函数确定Map的值类型并查找对应的bean。处理完成后,将bean名称添加至autowiredBeanNames,直接返回包含映射关系的map。
- 对于以上情况之外的其他类型,函数返回null,表示无法解析出符合条件的bean。
总之,此函数负责在Spring框架中实现复杂类型的自动装配,确保依赖项能够正确地从IoC容器中解析并初始化。
这里扩展一下,解释一下ResolvableType,如下面的代码例子
java
@Service
public class UserService {
private UserRepository[] userRepositoryArray;
@Autowired
public UserService(UserRepository[] repositories) {
this.userRepositoryArray = repositories;
}
// ...
}
@Repository
public interface UserRepository {
// ...
}
@Component("userRepository1")
public class UserRepositoryImpl1 implements UserRepository {
// 实现方法...
}
@Component("userRepository2")
public class UserRepositoryImpl2 implements UserRepository {
// 实现方法...
}
在上述示例中
ResolvableType
和DependencyDescriptor
的的作用是这样的:- ResolvableType: ResolvableType 是Spring框架中用于
处理泛型类型
的一种工具类
。它提供了获取和解析
复杂类型信息的能力,包括但不限于泛型参数、数组元素类型
等。 -
- 例如,在数组类型的注入场景中,当我们有
UserRepository[] userRepositoryArray
这样的字段时 descriptor.getResolvableType()
将返回一个表示该数组类型的ResolvableType
对象。- 结合
resolveMultipleBeans
源码来解释,此时resolvableType
就是UserRepository[]
这个类型的泛型工具类。 - 然后通过调用
.getComponentType().resolve()
来获取数组元素的具体类型(在这个例子中是UserRepository
类型),所以此时componentType = resolvableType.getComponentType().resolve()
;就是UserRepository
类型。 - 这样做的目的是为了准确地知道应该查找哪些bean进行注入,并确保转换后的数组元素与预期类型一致。
- 例如,在数组类型的注入场景中,当我们有
findAutowireCandidates
在自动装配过程中查找符合要求的bean实例。
java
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* @param beanName 即将被自动装配的bean的名称。
* @param requiredType 需要寻找的实际类型,即要匹配的目标类型,可能是数组组件类型或集合元素类型。
* @param descriptor 依赖描述符,用于描述当前依赖关系,如是否要求具有特定的注解 qualifier 等。
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 候选bean名称
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
// 尝试从缓存中获取与requiredType兼容的bean实例
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
// 获取缓存中的bean 类型
Class<?> autowiringType = classObjectEntry.getKey();
// 类型是否与requiredType一样
if (autowiringType.isAssignableFrom(requiredType)) {
// 获取 bean 实例
Object autowiringValue = classObjectEntry.getValue();
// 析并转换给定的 autowiringValue,使其能够适配 requiredType 类型。
// autowiringValue:这是从 resolvableDependencies 映射中获取的原始依赖值,它可以是一个bean实例、一个bean名称或者是某种表达式等,代表了某种待注入的依赖项
// requiredType:是当前需要自动装配的目标类型,即我们期望将 autowiringValue 转换为的类型。
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
// 如果autowiringValue是requiredType的类或字类的实例,那么则说明满足注入的要求,添加到结果集合中,待后续处理
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
// 不是自引用 && 是自动装配候选
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 将候选bean名称及其实例添加到结果集
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 没有找到多个匹配项的情况下,会进一步考虑包含自身引用的情况
if (result.isEmpty()) {
// 是否是接口、数组类、集合类、映射类
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
// 降级寻找依赖
// 降级版本的依赖描述符(fallback descriptor),这个降级描述符在自动装配过程中用于处理非严格匹配的情况
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) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
-
使用
BeanFactoryUtils.beanNamesForTypeIncludingAncestors
方法根据requiredType
获取上下文中所有匹配(包括父级上下文中的)的候选bean名称
,并存储到candidateNames
数组中。 -
初始化一个
LinkedHashMap result
,用于存放找到的符合条件的bean
实例及其名称
。 -
遍历
this.resolvableDependencies
映射,尝试从中找到可以直接使用的、与requiredType兼容的bean实例。如果找到并满足条件,则将其添加到结果集中,这个缓存集合是通过registerResolvableDependency
,这个方法注册进来的,前面的文章有提过。 -
遍历第一步得到的所有候
选bean名称
,对每个候选bean进行以下判断:- 检查该bean是否为
自引用
(即候选bean是否与待装配bean相同),如果是则跳过。 - 判断候选bean是否满足
自动装配
候选条件(通过isAutowireCandidate
方法实现)。 - 如果满足条件,则调用
addCandidateEntry
方法将候选bean名称及其实例添加到结果集。
- 检查该bean是否为
-
若在前四步未能找到任何匹配项,则考虑备选方案(
fallback匹配
)。首先创建一个降级依赖描述符fallbackDescriptor
,再次遍历候选bean名称列表,检查候选bean是否满足降级条件后加入结果集。 -
最后,在没有找到多个匹配项的情况下,会
进一步考虑包含自身引用的情况
,但排除直接引用自身
的集合元素情况,符合条件的也加入结果集。 -
返回最终填充好的结果集
result
,其中包含了所有找到的与requiredType匹配的bean实例及其名称。
这个函数主要用于支持自动装配功能,帮助Spring容器在配置和初始化bean时,依据其依赖关系自动关联合适的bean实例。
这里解释一下第五点,什么是降级依赖描述符DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch()
java
@Service("importantService")
public class ImportantServiceImpl implements ImportantService {
// ...
}
@Service
@Qualifier("fastDataSource")
public class FastDataSource implements DataSource {
// ...
}
@Service
public class ApplicationConfig {
@Autowired
private ImportantService importantService;
@Autowired
@Qualifier("fastDataSource") // 这是一个严格匹配的数据源
private DataSource dataSource;
}
- 如上面的例子,在自动装配过程中,Spring容器会为ApplicationConfig类中的字段生成对应的依赖描述符。
- 对于
importantService
字段,依赖描述符将要求查找类型为ImportantService
的所有候选bean,并且由于没有附加任何qualifier
注解,它将尝试找到所有实现该接口
的bean进行匹配。 - 对于
dataSource
字段,依赖描述符不仅要求类型为DataSource
,还要求具有```@Qualifier("fastDataSource")``注解。这意味着它需要寻找一个名为"fastDataSource"
的或者具有相同qualifier注解的DataSource类型的bean
。 -
- 现在,假设在某些情况下(例如,
@Qualifier("fastDataSource")
标注的bean不存在
),无法根据原始依赖描述符
找到合适的DataSource
实例。 - 这时,调用
descriptor.forFallbackMatch()
可能会返回一个新的降级依赖描述符
,这个新的描述符可能忽略
了qualifier
的要求,仅检查类型
是否匹配,从而能够找到其他未明确指定
但符合数据源类型
的候选bean。
- 现在,假设在某些情况下(例如,
总之,descriptor.forFallbackMatch()是为了在无法满足原始依赖条件时,提供一种放宽约束、扩大搜索范围以解决依赖注入问题的方式。
applyPropertyValues
主要作用是将给定的
属性值(pvs)
应用到由bw
包装的目标bean
对象上,同时解析其中可能存在的对其他bean的引用,并进行深度复制以避免对原始属性值的永久修改
java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
// 待转换的属性值列表
MutablePropertyValues mpvs = null;
// 原始属性值列表
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues _mpvs) {
mpvs = _mpvs;
// 如果 mpvs已经转换 则可以尝试直接使用
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
// 设置值
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
// 获取原始列表值
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
// 已转换过的放到 deepCopy中
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
// 获取名称
String propertyName = pv.getName();
// 获取原始值
Object originalValue = pv.getValue();
// 判断是否需要自动装配
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
// 获取 set 方法
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
// 因为自动装配是通过 set 方法进行注入的,set方法为 null 则直接抛异常
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
// 完成转换的值
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue typedStringValue &&
!typedStringValue.isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
// 设置值
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
-
首先检查提供的
PropertyValues
实例(pvs)是否为空。如果为空,则直接返回。 -
如果pvs非空,根据其类型创建或获取一个可变的
MutablePropertyValue
s实例(mpvs),并获取原始属性值列表。 -
判断
pvs
是否已经转换过
,如果是且已转换完成,则尝试直接使用转换后的属性值通过bw.setPropertyValues(mpvs)
设置到目标bean上,若出现异常则抛出BeanCreationException。 -
对于未转换或需要进一步处理的属性值,创建一个新的深度复制列表(
deepCopy
),并遍历原始属性值:- 检查每个属性值是否已转换,已转换的直接添加到deepCopy中。
- 对于未转换的属性值,调用
BeanDefinitionValueResolver
来解析和解决可能存在的bean引用
或其他运行时表达式
。 - writeMethod == nul这里会抛异常,是因为 spring 的自动装配是通过 set 方法完成的,有些也可以通过构造器注入,所以这里所以没有暴露 set 方法,就直接抛异常。之前我在这里就有疑问?
-
我们在日常开发的时候,经常在写 service 的时候,直接一个@Autowire 注解搞定,什么都没有写,这是怎么注入的呢?
-
这是因为Spring默认支持字段级别的自动注入。当Spring容器初始化一个bean时,它会检测该bean的所有字段,并查找带有@Autowired、@Inject等注解的字段,然后根据类型或名称从IoC容器中找到匹配的bean进行注入。
- 根据需要进行类型转换,利用
TypeConverter
将解析后的值转换为目标bean
属性期望的类型。 - 将转换后的值存储回
PropertyValue
实例,标记为已转换,并添加到deepCopy中。
-
最后,使用包含所有已处理过的属性值的新MutablePropertyValues实例(基于deepCopy)来设置目标bean的属性值,如果在此过程中出现异常,同样抛出BeanCreationException。
这个函数主要服务于Spring框架在初始化bean的过程中,处理bean定义中的属性注入逻辑
至此,spring 的自动装配已经完成啦!接下来就是 bean 的初始化了。
总结
populateBean方法主要用于完成对@Autowired、@Resource、@Value等注解标注的属性的填充。
流程:
Spring通过createBeanInstance方法创建了对象。 在对象被创建完成后,调用了populateBean方法。 populateBean方法会对@Autowired、@Resource、@Value等注解标注的属性进行填充。