✒️ 作者 - Lex 📝 博客 - CSDN | 掘金 📚 源码地址 - GitHub
resolveDependency
是 Spring 框架中 ConfigurableListableBeanFactory
接口中定义的一个方法。这个方法的核心功能是解析并提供 bean 的依赖项。它主要在处理 @Autowired
, @Inject
,@Value
这样的自动装配场景时起作用。
Spring IOC 容器中的一个核心方法,用于解析 bean 之间的依赖关系。当容器需要知道应该为特定的 bean、字段、构造函数或方法注入哪个其他 bean 时,就会调用这个方法。
/**
* 在此工厂中定义的 beans 之间,解析指定的依赖项。
*
* 该方法尝试匹配和返回一个适当的 bean 实例来满足给定的依赖描述符。
* 依赖描述符可以描述字段、方法或构造函数中的依赖。
*
* @param descriptor 描述依赖的对象,提供有关依赖类型、限定符等的详细信息。
* @param requestingBeanName 声明或请求依赖的 bean 的名称。这通常用于解决 bean 之间的循环依赖。
* @return 对应的 bean 实例以满足该依赖,如果没有合适的匹配,则返回 null。
*
* @throws NoSuchBeanDefinitionException 当没有找到匹配的 bean 时抛出。
* @throws NoUniqueBeanDefinitionException 当存在多个可能的匹配并且没有明确的选择时抛出。
* @throws BeansException 如果由于其他原因解析失败则抛出。
*
* @since 2.5
* @see #resolveDependency(DependencyDescriptor, String, Set, TypeConverter) 用于更复杂的依赖解析场景,允许传递排除的 beans 和类型转换器。
*/
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
- 依赖描述符
- 该方法接收一个
DependencyDescriptor
参数,它描述了所需的依赖关系。这个描述符可以表示一个字段、方法参数或构造函数参数的依赖。
- 该方法接收一个
- 自动装配限定符
- 如果存在多个匹配的 bean,并且所需的依赖有
@Autowired
和@Qualifier
注解,那么resolveDependency
会考虑这些注解来确定正确的 bean。
- 如果存在多个匹配的 bean,并且所需的依赖有
- 解决循环依赖
- 该方法也会考虑循环依赖的问题。例如,如果 Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A,那么这种情况会被处理。
- 返回匹配的 bean
- 此方法尝试返回一个与描述符匹配的 bean 实例。如果找不到合适的 bean,它可能返回 null 或抛出一个异常,具体取决于描述符的设置。
- 异常处理
- 如果没有找到合适的 bean 或找到了多个合适的 bean 且没有明确的选择,该方法会抛出相应的异常。
- 其他 Considerations:
- 可以考虑其他因素,如
@Primary
注解。 - 对于基本类型或字符串类型的属性,可以解析
@Value
注解,从属性文件或环境变量中获取值。
- 可以考虑其他因素,如
首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext
(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration
组件类。代码调用了两个方法(methodResolveDependency
和 fieldResolveDependency
)来分别解析方法和字段的依赖。具体来说,它们会使用反射来获取目标方法或字段。创建一个描述这个方法或字段的 DependencyDescriptor
。使用 resolveDependency
方法来从 Spring 容器中解析真正的依赖。使用反射来将解析得到的依赖注入到目标对象中。在解析方法和字段的依赖之后,代码通过格式化的字符串打印了相关信息。例如,它显示了方法或字段的完全限定名称和解析得到的依赖对象的值。
public class ResolveDependencyApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
// 获得Bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 被注入对象
MyServiceB injectTarget = new MyServiceB();
System.out.println("Before MyServiceB = " injectTarget "\n");
methodResolveDependency(beanFactory, injectTarget, "setMethodMyServiceA");
fieldResolveDependency(beanFactory, injectTarget, "fieldMyServiceA");
fieldResolveDependency(beanFactory, injectTarget, "myPropertyValue");
System.out.println("After MyServiceB = " injectTarget "\n");
}
/**
* 解析方法依赖
*
* @param beanFactory
* @param injectTarget
*/
public static void methodResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) {
try {
// 1. 获取MyServiceB类中名为setMethodMyServiceA的方法的引用
Method method = injectTarget.getClass().getMethod(name, MyServiceA.class);
// 2. 创建一个描述此方法参数的DependencyDescriptor
DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(method, 0), true);
// 3. 使用BeanFactory来解析这个方法参数的依赖
Object value = beanFactory.resolveDependency(desc, null);
System.out.println("解析方法依赖结果:");
System.out.println("---------------------------------------------");
System.out.println(String.format("Name: %s.%s",method.getDeclaringClass().getName(),method.getName()));
System.out.println(String.format("Value: %s", value));
System.out.println("---------------------------------------------\n");
// 4. 使方法可访问(特别是如果它是private的)
ReflectionUtils.makeAccessible(method);
// 5. 使用反射调用这个方法,将解析得到的依赖注入到目标对象中
method.invoke(injectTarget, value);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析字段依赖
*
* @param beanFactory
* @param injectTarget
*/
public static void fieldResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) {
try {
// 1. 获取MyServiceB类中名为fieldMyServiceA的字段的引用
Field field = injectTarget.getClass().getDeclaredField(name);
// 2. 创建一个描述此字段的DependencyDescriptor
DependencyDescriptor desc = new DependencyDescriptor(field, true);
// 3. 使用BeanFactory来解析这个字段的依赖
Object value = beanFactory.resolveDependency(desc, null);
System.out.println("解析字段依赖结果:");
System.out.println("---------------------------------------------");
System.out.println(String.format("Name: %s.%s", field.getDeclaringClass().getName(), field.getName()));
System.out.println(String.format("Value: %s", value));
System.out.println("---------------------------------------------\n");
// 4. 使字段可访问(特别是如果它是private的)
ReflectionUtils.makeAccessible(field);
// 5. 使用反射设置这个字段的值,将解析得到的依赖注入到目标对象中
field.set(injectTarget, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在MyConfiguration
类中,使用了@ComponentScan("com.xcs.spring")
注解告诉 Spring 在指定的包(在这里是 "com.xcs.spring
")及其子包中搜索带有 @Component
、@Service
、@Repository
和 @Controller
等注解的类,并将它们自动注册为 beans。这样,spring就不必为每个组件明确写一个 bean 定义。Spring 会自动识别并注册它们。另外使用@PropertySource
注解从类路径下的application.properties
文件中加载属性。
@Configuration
@ComponentScan("com.xcs.spring")
@PropertySource("classpath:application.properties")
public class MyConfiguration {
}
application.properties
文件在src/main/resources
目录中,并添加以下内容。
my.property.value = Hello from Environment!
MyService
是一个简单的服务类,但我们没有定义任何方法或功能。
@Service
public class MyServiceA {
}
首先 MyServiceB
没有被 Spring 托管,那么它在代码中的表现就与一个普通的 Java 类没有什么不同。虽然 MyServiceB
本身不是 Spring 托管的,但 ResolveDependencyApplication
类中,我给大家展示了如何使用 Spring 的底层 API 手动解析和注入依赖。
- 字段
myPropertyValue
- 虽然它有一个
@Value
注解,但由于MyServiceB
不是一个 Spring 管理的 bean,所以这个注解不会自动被解析。
- 虽然它有一个
- 字段
myServiceA
和fieldMyServiceA
- 由于没有自动的 Spring 依赖注入,这两个字段默认为
null
。
- 由于没有自动的 Spring 依赖注入,这两个字段默认为
- 方法
setMyServiceA
- 这是一个普通的 setter 方法。但在
MyServiceB
不被 Spring 托管的情况下,它只是一个普通的 setter。
- 这是一个普通的 setter 方法。但在
- 方法
toString
- 该方法为该类提供了一个自定义的字符串表示。这与
MyServiceB
是否被 Spring 托管无关。
- 该方法为该类提供了一个自定义的字符串表示。这与
public class MyServiceB {
/**
* 方法注入
*/
private MyServiceA methodMyServiceA;
/**
* 字段注入
*/
private MyServiceA fieldMyServiceA;
/**
* 字段注入 (环境变量)
*/
@Value("${my.property.value}")
private String myPropertyValue;
public void setMethodMyServiceA(MyServiceA methodMyServiceA){
this.methodMyServiceA = methodMyServiceA;
}
@Override
public String toString() {
return "MyServiceB{"
"myPropertyValue='" myPropertyValue '\''
", methodMyServiceA=" methodMyServiceA
", fieldMyServiceA=" fieldMyServiceA
'}';
}
}
运行结果发现,使用了 Spring 的底层 resolveDependency
方法来为 MyServiceB
类的字段和方法手动注入依赖。虽然在常规的 Spring 开发中我们通常不这样做(因为 Spring 提供了更高级的自动化工具进行依赖注入),但这主要目的是给大家展示 Spring 如何在底层工作原理,并提供了一种手动控制依赖注入的方法。
Before MyServiceB = MyServiceB{myPropertyValue='null', myServiceA=null, fieldMyServiceA=null}
解析方法依赖结果:
---------------------------------------------
Name: com.xcs.spring.service.MyServiceB.setMyServiceA
Value: com.xcs.spring.service.MyServiceA@202b0582
---------------------------------------------
解析字段依赖结果:
---------------------------------------------
Name: com.xcs.spring.service.MyServiceB.fieldMyServiceA
Value: com.xcs.spring.service.MyServiceA@202b0582
---------------------------------------------
解析字段依赖结果:
---------------------------------------------
Name: com.xcs.spring.service.MyServiceB.myPropertyValue
Value: Hello from Environment!
---------------------------------------------
After MyServiceB = MyServiceB{myPropertyValue='Hello from Environment!', myServiceA=com.xcs.spring.service.MyServiceA@202b0582, fieldMyServiceA=com.xcs.spring.service.MyServiceA@202b0582}
通过使用@Value
注解,我们可以请求一个特定的环境属性或变量。例如,我们可能会这样请求一个名为my.property.value
的属性。
sequenceDiagram
Title: resolveDependency方法解析环境属性和变量时序图
ResolveDependencyApplication-->>AbstractAutowireCapableBeanFactory:resolveDependency(descriptor,requestingBeanName)
note over AbstractAutowireCapableBeanFactory: 请求解析依赖
AbstractAutowireCapableBeanFactory->>DefaultListableBeanFactory:resolveDependency(descriptor, requestingBeanName, null, null)
note over DefaultListableBeanFactory: 转到具体的Bean工厂进行解析
DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)
note over DefaultListableBeanFactory: 进行实际的依赖解析
DefaultListableBeanFactory->>DefaultListableBeanFactory:getAutowireCandidateResolver()
note over DefaultListableBeanFactory: 获取当前的依赖解析策略
DefaultListableBeanFactory->>QualifierAnnotationAutowireCandidateResolver:getSuggestedValue(descriptor)
note over QualifierAnnotationAutowireCandidateResolver: 基于给定的描述符查找建议的值
QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:findValue(annotationsToSearch)
note over QualifierAnnotationAutowireCandidateResolver: 在指定的注解中寻找值
QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:extractValue(attr)
note over QualifierAnnotationAutowireCandidateResolver: 从注解属性中提取值
QualifierAnnotationAutowireCandidateResolver->>DefaultListableBeanFactory:返回@Value注解的表达式
note over DefaultListableBeanFactory: 解析注解中的表达式或值
DefaultListableBeanFactory->>AbstractBeanFactory:resolveEmbeddedValue(value)
note over AbstractBeanFactory: 解析嵌入的值(如占位符或SpEL表达式)
DefaultListableBeanFactory->>AbstractBeanFactory:evaluateBeanDefinitionString(strVal, bd)
note over AbstractBeanFactory: 对bean定义字符串进行评估(可能是一个表达式)
DefaultListableBeanFactory->>AbstractBeanFactory:getTypeConverter()
note over AbstractBeanFactory: 获取用于类型转换的转换器
DefaultListableBeanFactory->>TypeConverterSupport:convertIfNecessary(value, type, typeDescriptor())
note over TypeConverterSupport: 根据需要将值转换为指定的类型
TypeConverterSupport->>DefaultListableBeanFactory:返回类型转换的结果
note over DefaultListableBeanFactory: 用转换后的值继续解析流程
DefaultListableBeanFactory->>AbstractAutowireCapableBeanFactory:返回环境属性
AbstractAutowireCapableBeanFactory->>ResolveDependencyApplication:返回环境属性
这是其主要的功能。当我们有一个bean,它需要另一个bean的实例时,resolveDependency
会为我们找到并提供所需的bean。例如,如果一个MyServiceB
类需要一个MyServiceA
类的实例,那么resolveDependency
可以为MyServiceB
类提供一个MyServiceA
的实例。
sequenceDiagram
Title: resolveDependency方法解析Bean依赖时序图
ResolveDependencyApplication-->>AbstractAutowireCapableBeanFactory:resolveDependency(descriptor,requestingBeanName)
note right of AbstractAutowireCapableBeanFactory: 开始解析依赖请求
AbstractAutowireCapableBeanFactory->>DefaultListableBeanFactory:resolveDependency(descriptor, requestingBeanName, null, null)
note right of DefaultListableBeanFactory: 委托给具体的Bean工厂进行依赖解析
DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)
note right of DefaultListableBeanFactory: 执行具体的依赖解析逻辑
DefaultListableBeanFactory->>DefaultListableBeanFactory:resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter)
note right of DefaultListableBeanFactory: 解析满足条件的多个Beans
DefaultListableBeanFactory->>DefaultListableBeanFactory:findAutowireCandidates(beanName, type, descriptor)
note right of DefaultListableBeanFactory: 查找适合自动装配的候选Beans
DefaultListableBeanFactory->>DefaultListableBeanFactory:isSelfReference(beanName, candidate)
note right of DefaultListableBeanFactory: 检查bean是否引用了自身
DefaultListableBeanFactory->>DefaultListableBeanFactory:isAutowireCandidate(candidate, descriptor)
note right of DefaultListableBeanFactory: 检查bean是否是一个合适的自动装配候选
DefaultListableBeanFactory->>DefaultListableBeanFactory:addCandidateEntry(result, candidate, descriptor, requiredType)
note right of DefaultListableBeanFactory: 将找到的候选添加到结果集中
DefaultListableBeanFactory->>DependencyDescriptor:resolveCandidate(candidateName, requiredType, beanFactory)
note right of DependencyDescriptor: 尝试解析并返回候选Bean
DependencyDescriptor->>AbstractBeanFactory:getBean(String name)
note right of AbstractBeanFactory: 请求获取指定名称的bean
AbstractBeanFactory->>DependencyDescriptor:返回候选的Bean对象
note right of DependencyDescriptor: 返回找到的Bean实例
DependencyDescriptor->>DefaultListableBeanFactory:返回候选的Bean对象
note right of DefaultListableBeanFactory: 将Bean实例返回给Bean工厂
DefaultListableBeanFactory->>DefaultListableBeanFactory:determineAutowireCandidate(matchingBeans, descriptor)
note right of DefaultListableBeanFactory: 从匹配的Beans中确定自动装配的候选
DefaultListableBeanFactory->>AbstractAutowireCapableBeanFactory:返回Bean
note right of AbstractAutowireCapableBeanFactory: 将确定的Bean返回给上一级的Bean工厂
AbstractAutowireCapableBeanFactory->>ResolveDependencyApplication:返回bean
note right of ResolveDependencyApplication: 返回bean给依赖解析的请求者
在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
方法中,此方法将尝试使用懒加载代理或直接解析依赖项,具体使用哪种方式取决于上下文及其他配置(本次研究环境属性)。
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代码部分省略以简化]
// 尝试为依赖获取懒加载代理
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
// 如果懒加载代理不可用,则执行实际的依赖解析
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法中,此代码段尝试解析一个依赖,先查找建议的值(@Value
注解),然后进行必要的类型转换。
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
try {
// ... [代码部分省略以简化]
// 获取依赖描述符中定义的依赖类型
Class<?> type = descriptor.getDependencyType();
// 步骤1: 从自动装配候选解析器中获取建议的依赖值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// 如果建议的值是一个字符串
if (value instanceof String) {
// 步骤2: 解析嵌入在字符串中的值(例如,从环境变量中查找)
String strVal = resolveEmbeddedValue((String) value);
// 获取bean定义,如果beanName存在且已经在容器中,则获取与beanName相关的bean定义
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
// 步骤3: 对字符串值进行求值,可能会处理表达式之类的内容
value = evaluateBeanDefinitionString(strVal, bd);
}
// 获取类型转换器,如果传入了外部转换器则使用它,否则使用默认的转换器
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 步骤4: 尝试进行必要的类型转换
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// 处理不支持的操作异常(具体实现已省略)
}
}
// ... [代码部分省略以简化]
}
finally {
// ... [代码部分省略以简化]
}
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤1。
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#getSuggestedValue
方法中,主要目的是从一个DependencyDescriptor
中提取建议的值。DependencyDescriptor
可以描述一个bean的属性(可能是一个字段或者方法参数)。
@Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
// 从字段的注解中尝试找到建议的值
Object value = findValue(descriptor.getAnnotations());
// 如果在字段上没有找到,则从方法的注解中尝试找到
if (value == null) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
value = findValue(methodParam.getMethodAnnotations());
}
}
// 返回建议的值,如果没有找到则返回null
return value;
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#findValue
方法中,主要目的是从提供的注解数组中寻找一个特定的注解(@Value
)并提取其值。
@Nullable
protected Object findValue(Annotation[] annotationsToSearch) {
// 如果注解数组非空,则进入检查逻辑
if (annotationsToSearch.length > 0) {
// 从注解数组中获取合并后的特定注解属性(这里的特定注解可能是@Value)
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
// 如果找到了相应的注解属性,则提取它的值
if (attr != null) {
return extractValue(attr);
}
}
// 没有找到相应的注解属性或值,返回null
return null;
}
在org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#extractValue
方法中,从@Value
注解属性中,提取一个value
属性值。
protected Object extractValue(AnnotationAttributes attr) {
// 从注解属性中尝试获取'VALUE'(一般为"value")的属性值
Object value = attr.get(AnnotationUtils.VALUE);
// 如果该属性值为空,那么抛出一个异常
if (value == null) {
throw new IllegalStateException("Value annotation must have a value attribute");
}
// 返回提取的值
return value;
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤2。
在org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue
方法中,主要接受一个字符串值,并利用StringValueResolver
逐一对其进行解析StringValueResolver
逐一对其进行解析,然后返回最终解析后的字符串值。
@Override
@Nullable
public String resolveEmbeddedValue(@Nullable String value) {
// 如果传入的值为空,直接返回null
if (value == null) {
return null;
}
// 初始化结果为传入的值
String result = value;
// 遍历当前对象中所有的字符串值解析器
for (StringValueResolver resolver : this.embeddedValueResolvers) {
// 使用解析器解析当前的结果值
result = resolver.resolveStringValue(result);
// 如果解析后的值为空,直接返回null
if (result == null) {
return null;
}
}
// 返回最终解析后的字符串值
return result;
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤3。
在org.springframework.beans.factory.support.AbstractBeanFactory#evaluateBeanDefinitionString
方法中,主要负责对一个Bean定义中的字符串值(可能是一个表达式${my.property.value}
)进行求值。如果配置了beanExpressionResolver
,则会使用它进行求值;如果没有,则直接返回原始值。
@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
// 如果没有设置beanExpressionResolver(即解析表达式的解析器),直接返回原始值
if (this.beanExpressionResolver == null) {
return value;
}
Scope scope = null; // 定义作用域变量
if (beanDefinition != null) {
// 从Bean定义中获取作用域名称
String scopeName = beanDefinition.getScope();
if (scopeName != null) {
// 获取该作用域的具体实例
scope = getRegisteredScope(scopeName);
}
}
// 使用beanExpressionResolver对字符串值进行求值,并返回结果
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤4。
在org.springframework.beans.TypeConverterSupport#convertIfNecessary(value,requiredType,typeDescriptor)
方法中,首先确保有一个可用的typeConverterDelegate
来进行实际的转换工作,然后尝试将给定值转换为指定的类型。
@Nullable
@Override
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
// 断言,确保typeConverterDelegate(类型转换代理)不为空
Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
try {
// 通过typeConverterDelegate进行类型转换
return this.typeConverterDelegate.convertIfNecessary(null, null, value, requiredType, typeDescriptor);
}
// ... [代码部分省略以简化]
}
在org.springframework.beans.TypeConverterDelegate#convertIfNecessary(propertyName, oldValue, newValue,requiredType, typeDescriptor)
方法中,主要考虑了许多转换场景,使其能够处理各种类型和结构的数据。
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// 查找对于此类型的自定义编辑器
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
// 如果没有自定义编辑器但指定了自定义ConversionService,则尝试转换
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
// ... [代码部分省略以简化]
}
Object convertedValue = newValue;
// 如果值不是所需的类型,进行转换
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
// ... [代码部分省略以简化]
}
boolean standardConversion = false;
// 尝试应用标准类型转换规则(如果适用)
if (requiredType != null) {
// 对不同类型的专门转换逻辑
if (convertedValue != null) {
if (Object.class == requiredType) {
return (T) convertedValue;
}
// 这里根据不同的requiredType类型进行了不同的转换处理,例如处理数组、集合、映射、枚举等不同类型的转换。
else if (requiredType.isArray()) {
// ... [代码部分省略以简化]
}
else if (convertedValue instanceof Collection) {
// ... [代码部分省略以简化]
}
else if (convertedValue instanceof Map) {
// ... [代码部分省略以简化]
}
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
// ... [代码部分省略以简化]
}
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// ... [代码部分省略以简化]
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
// ... [代码部分省略以简化]
}
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
// ... [代码部分省略以简化]
}
}
else {
// convertedValue == null
if (requiredType == Optional.class) {
convertedValue = Optional.empty();
}
}
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
// ... [代码部分省略以简化]
}
}
if (conversionAttemptEx != null) {
// ... [代码部分省略以简化]
}
return (T) convertedValue;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
方法中,此方法将尝试使用懒加载代理或直接解析依赖项,具体使用哪种方式取决于上下文及其他配置(本次研究Bean依赖)。
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代码部分省略以简化]
// 尝试为依赖获取懒加载代理
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
// 如果懒加载代理不可用,则执行实际的依赖解析
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法中,主要是解析并注入依赖项。首先,它尝试解析多个Bean候选项(例如,当需要注入的是List或Map类型)。如果没有找到匹配的Bean,它可能会抛出异常。如果有多个匹配的Bean,它会尝试确定最合适的一个进行注入。如果只有一个匹配的Bean,则直接进行注入。
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ... [代码部分省略以简化]
try {
// ... [代码部分省略以简化]
// 步骤1: 尝试解析多个Bean候选项。例如,当需要注入List或Map类型的时候
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 步骤2: 寻找符合类型匹配的Bean候选项
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 步骤3: 如果有多个匹配的Bean,则尝试确定哪一个是最合适的
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// 对于非必需的Collection/Map,忽略非唯一的情况
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 只有一个匹配的Bean
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 记录已经自动装配的Bean名称
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 如果候选对象是一个类,则尝试解析为实际的Bean实例
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
// ... [代码部分省略以简化]
return result;
}
finally {
// ... [代码部分省略以简化]
}
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤1。
在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveMultipleBeans
方法中,解决了当依赖是多值类型(如Stream
、数组、Collection
、Map
)时如何自动注入对应的Bean。该方法首先判断依赖的类型,然后针对不同类型进行解析。对于每种类型,它都会查找所有匹配的Bean候选项,并按需要转换和排序它们。
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
// 判断依赖是否为Java 8 Stream类型
if (descriptor instanceof StreamDependencyDescriptor) {
// ... [代码部分省略以简化]
}
// 判断依赖是否为数组类型
else if (type.isArray()) {
// ... [代码部分省略以简化]
return result;
}
// 判断依赖是否为集合接口类型
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
// ... [代码部分省略以简化]
return result;
}
// 判断依赖是否为Map类型
else if (Map.class == type) {
// ... [代码部分省略以简化]
return matchingBeans;
}
else {
return null;
}
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤2。
在org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
方法中,主要目的是确定哪些Bean适合自动注入给定的依赖。它首先从当前的BeanFactory
及其祖先中获取所有可能的候选Bean,然后根据各种条件(如类型匹配、qualifiers等)过滤这些候选项。如果在首次查找中没有找到任何匹配的bean,它还会尝试回退匹配来找到适当的bean。
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 1. 从BeanFactory及其祖先中获取所有可能的候选bean名称,这些bean的类型与所需的类型匹配。
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
// 2. 初始化一个空的结果映射,用于保存候选bean。
Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
// 3. 遍历预定义的可解析的依赖项。
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
// 4. 检查当前的依赖项是否与所需的类型兼容。
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
// 5. 对当前的值进行自动装配的解析。
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
// 6. 如果解析后的值与所需的类型相匹配,将其添加到结果映射中。
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 7. 遍历所有可能的候选bean名称。
for (String candidate : candidateNames) {
// 8. 如果当前bean名称不是对自己的引用,并且它是一个有效的自动装配候选项,则将其添加到结果映射中。
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 9. 如果没有找到任何匹配的候选bean。
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// 10. 为回退匹配创建一个新的描述符。
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
// 11. 重新遍历所有候选bean名称。
for (String candidate : candidateNames) {
// 12. 如果当前bean名称不是对自己的引用,并且它是一个有效的回退匹配的候选项,则将其添加到结果映射中。
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 13. 如果还没有找到任何匹配的候选bean,考虑自引用的bean作为候选bean。
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);
}
}
}
}
// 14. 返回找到的候选bean的映射。
return result;
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#addCandidateEntry
方法中,根据不同的DependencyDescriptor
类型和其他条件决定如何将候选Bean及其实例或类型添加到提供的映射中。对于需要多个元素的依赖项(如集合或数组),它会添加所有的Bean实例;对于单例或需要排序的流描述符,它会添加Bean实例;而对于其他情况,只会添加Bean的类型。
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {
// 如果DependencyDescriptor是一个MultiElementDescriptor(意味着描述的依赖可能有多个元素,例如集合或数组)
if (descriptor instanceof MultiElementDescriptor) {
// 解析候选Bean的实例
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
// 如果解析的实例不是NullBean(即一个占位符对象,代表null值),则将其添加到候选列表中
if (!(beanInstance instanceof NullBean)) {
candidates.put(candidateName, beanInstance);
}
}
// 如果当前Bean是单例,或者DependencyDescriptor是一个StreamDependencyDescriptor并且有序
else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor &&
((StreamDependencyDescriptor) descriptor).isOrdered())) {
// 解析候选Bean的实例
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
// 如果解析的实例是NullBean,则将null添加到映射中,否则添加实际的Bean实例
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
}
// 其他情况下,只将Bean的类型而不是实例添加到映射中
else {
candidates.put(candidateName, getType(candidateName));
}
}
在org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate
方法中,最后发现,在Spring的依赖注入过程中,当一个bean依赖于另一个bean时,底层的实现最终会通过getBean
方法从容器中获取所依赖的bean实例。
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
// 根据提供的bean名称从beanFactory中获取并返回bean的实例
return beanFactory.getBean(beanName);
}
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
方法步骤3。
在org.springframework.beans.factory.support.DefaultListableBeanFactory#determineAutowireCandidate
方法中,主要是存在多个候选bean时确定应该自动注入哪一个。它首先检查是否有被标记为"primary"的bean,然后检查是否有优先级最高的bean。如果这两种方法都无法确定,它会回退到查找与依赖描述符匹配的bean名字或是否该bean实例存在于可解析的依赖中。如果仍然没有找到匹配的bean,它会返回null。
@Nullable
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
// 获取依赖的类型
Class<?> requiredType = descriptor.getDependencyType();
// 确定是否有被标记为"primary"的候选bean
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
// 如果有主要的候选bean,则返回这个bean的名字
return primaryCandidate;
}
// 检查是否有最高优先级的候选bean
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
// 如果有优先级最高的候选bean,则返回这个bean的名字
return priorityCandidate;
}
// 如果上述两种方法都无法确定一个bean,那么进行回退处理
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
// 如果候选bean实例存在于可解析的依赖中,或者候选bean的名字与描述符中的依赖名字匹配,则选择该候选bean
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
// 如果没有匹配的bean,返回null
return null;
}
- 循环依赖
- 确保不引入循环依赖,否则会导致 Bean 创建失败。Spring 有一些内置的检测机制,但在自定义逻辑时仍需格外注意。
- 候选 Bean 的选择
- 在有多个候选 Bean 可用于注入时,该如何选择是一个重要问题。Spring 提供了
@Primary
,@Priority
等注解来辅助决策,但你可能需要考虑其他因素。
- 在有多个候选 Bean 可用于注入时,该如何选择是一个重要问题。Spring 提供了
- 自定义类型转换
- 如果需要,应确保提供适当的类型转换逻辑,以将 Bean 转换为所需的类型。
- 性能考虑
- 避免不必要的重复查找或计算。在可能的情况下,考虑缓存结果,特别是对于高频率的依赖查找。
- 生命周期和作用域
- 确保考虑到目标 Bean 的生命周期和作用域。例如,一个 prototype 作用域的 Bean 不应该被注入到一个 singleton 作用域的 Bean 中,除非你明确知道这样做的后果。
- 考虑非常规的依赖源
resolveDependency
可能需要考虑来自非常规来源的依赖,如FactoryBeans
、BeanFactory
或其他特殊的依赖提供者。
-
明确环境和配置
- 在示例中,使用了
AnnotationConfigApplicationContext
作为 Spring 的应用上下文,它基于 Java 注解来配置和初始化 Spring 容器。指定了MyConfiguration
类作为配置源,它用于引导整个应用程序的上下文环境。
- 在示例中,使用了
-
简化依赖解析
- 通过将依赖解析过程封装到具体的方法中 (
methodResolveDependency
和fieldResolveDependency
),代码的逻辑变得清晰且可维护。
- 通过将依赖解析过程封装到具体的方法中 (
-
利用Spring的底层API
- 虽然大部分时间我们依赖于 Spring 的自动化特性进行依赖注入,但在这个实践中,我们深入地使用了 Spring 的底层
resolveDependency
方法来手动解析和注入依赖。这不仅展示了 Spring 的内部工作原理,还提供了当自动注入不适用时的替代解决方案。
- 虽然大部分时间我们依赖于 Spring 的自动化特性进行依赖注入,但在这个实践中,我们深入地使用了 Spring 的底层
-
手动依赖注入的用例
- 即使
MyServiceB
不是由 Spring 托管的 Bean,我们仍然能够使用 Spring 的机制为它解析和注入所需的依赖。这种能力在某些特定场景下可能非常有用,例如当我们需要将 Spring 与非 Spring 管理的代码集成时。
- 即使
-
使用反射增强灵活性
- 通过反射API,我们能够动态地访问和操作目标对象的方法和字段,无论它们是否是公开的。这为我们提供了极大的灵活性,特别是当我们需要操作第三方库中的类时。
-
确保配置的完整性
- 确保所需的所有配置资源,如
application.properties
文件,都在正确的位置并且被正确加载。在这个示例中,它被用来为MyServiceB
提供一个属性值。
- 确保所需的所有配置资源,如
-
验证和测试
- 最后,通过打印方法,确保了所有依赖都已正确解析和注入。在实际应用中,我们应该有相应的单元测试来验证这些行为。
解析环境变量
- 解析
@Value
注解doResolveDependency
方法首先检查是否存在一个建议的值,通常来自@Value
注解。如果找到这样的值,它会首先进行字符串替换(例如替换属性占位符),然后可能对该值进行求值(如果它是一个表达式),最后尝试将该值转换为目标类型。
- 类型转换
- 如果找到了一个建议的值,或者已经解析了一个依赖项但其类型与所需的类型不匹配,系统会尝试进行类型转换。Spring有一个强大的类型转换系统,能够处理各种各样的转换场景。
- 深入的类型转换
- 如果需要进行更复杂的类型转换(例如从集合到数组、从字符串到数字等),Spring提供了许多内置的转换规则来处理这些场景。
解析Bean依赖
- 依赖解析的起点
resolveDependency
是Spring的主要方法,用于解析bean的依赖关系。
- 懒加载代理判断
- 首先,尝试使用懒加载代理满足依赖关系。如果不能使用懒加载代理,它会进一步尝试解析依赖。
- 解析具体的依赖
- 在
doResolveDependency
中,根据依赖的类型,Spring可能尝试解析多个Bean候选项,如List或Map。它会搜索匹配的Bean,并根据条件(如类型、qualifiers等)选择合适的Bean进行注入。
- 在
- 多值依赖的处理
- 如果依赖是多值类型(如集合或映射),Spring将在
resolveMultipleBeans
中进行处理。
- 如果依赖是多值类型(如集合或映射),Spring将在
- 确定注入的Bean
- 如果有多个可能的Bean候选项,
determineAutowireCandidate
将帮助确定哪一个Bean是最佳的注入选择,这可能基于“primary”标记或Bean的优先级。
- 如果有多个可能的Bean候选项,
- 获取实际的Bean实例
- 在所有这些决策之后,Spring最终会通过
getBean
方法获取并返回所依赖的Bean实例。
- 在所有这些决策之后,Spring最终会通过