resolveDependency方法源码分析

master
xuchengsheng 2023-10-26 16:27:54 +08:00
parent daf9e1c8f6
commit 32b0053117
2 changed files with 653 additions and 7 deletions

View File

@ -1,6 +1,26 @@
## resolveDependency
- [resolveDependency](#resolvedependency)
- [一、基本信息](#一基本信息)
- [二、方法描述](#二方法描述)
- [三、方法源码](#三方法源码)
- [四、主要功能](#四主要功能)
- [五、最佳实践](#五最佳实践)
- [六、时序图](#六时序图)
- [解析环境变量](#解析环境变量)
- [解析Bean依赖](#解析bean依赖)
- [七、源码分析](#七源码分析)
- [解析环境变量](#解析环境变量-1)
- [解析Bean依赖](#解析bean依赖-1)
- [八、注意事项](#八注意事项)
- [九、总结](#九总结)
- [最佳实践总结](#最佳实践总结)
- [源码分析总结](#源码分析总结)
### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [我的CSDN]() 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading)
✒️ **作者** - Lex 📝 **博客** - [CSDN](https://blog.csdn.net/duzhuang2399) | [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [GitHub](https://github.com/xuchengsheng/spring-reading)
### 二、方法描述
@ -79,7 +99,7 @@ public class ResolveDependencyApplication {
*/
public static void methodResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) {
try {
// 1. 获取MyServiceB类中名为setMyServiceA的方法的引用
// 1. 获取MyServiceB类中名为setMethodMyServiceA的方法的引用
Method method = injectTarget.getClass().getMethod(name, MyServiceA.class);
// 2. 创建一个描述此方法参数的DependencyDescriptor
@ -239,7 +259,7 @@ After MyServiceB = MyServiceB{myPropertyValue='Hello from Environment!', myServi
### 六、时序图
#### 环境属性和变量
#### 解析环境变量
通过使用`@Value`注解,我们可以请求一个特定的环境属性或变量。例如,我们可能会这样请求一个名为`my.property.value`的属性。
@ -290,7 +310,7 @@ DefaultListableBeanFactory->>AbstractAutowireCapableBeanFactory:返回环境属
AbstractAutowireCapableBeanFactory->>ResolveDependencyApplication:返回环境属性
~~~
#### Bean依赖
#### 解析Bean依赖
这是其主要的功能。当我们有一个bean它需要另一个bean的实例时`resolveDependency` 会为我们找到并提供所需的bean。例如如果一个`MyServiceB`类需要一个`MyServiceA`类的实例,那么`resolveDependency` 可以为`MyServiceB`类提供一个`MyServiceA`的实例。
@ -345,14 +365,639 @@ note right of ResolveDependencyApplication: 返回bean给依赖解析的请求
~~~
### 七、源码分析
#### 解析环境变量
在`org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency`方法中,此方法将尝试使用懒加载代理或直接解析依赖项,具体使用哪种方式取决于上下文及其他配置(本次研究环境属性)。
```java
@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`注解),然后进行必要的类型转换。
```java
@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的属性可能是一个字段或者方法参数
```java
@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`)并提取其值。
```java
@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`属性值。
```java
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`逐一对其进行解析,然后返回最终解析后的字符串值。
```java
@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`,则会使用它进行求值;如果没有,则直接返回原始值。
```java
@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`来进行实际的转换工作,然后尝试将给定值转换为指定的类型。
```java
@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)`方法中,主要考虑了许多转换场景,使其能够处理各种类型和结构的数据。
```java
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;
}
```
#### 解析Bean依赖
在`org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency`方法中此方法将尝试使用懒加载代理或直接解析依赖项具体使用哪种方式取决于上下文及其他配置本次研究Bean依赖
```java
@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则直接进行注入。
```java
@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候选项并按需要转换和排序它们。
```java
@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。
```java
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的类型。
```java
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实例。
```java
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。
```java
@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;
}
```
### 八、注意事项
1. **循环依赖**
+ 确保不引入循环依赖,否则会导致 Bean 创建失败。Spring 有一些内置的检测机制,但在自定义逻辑时仍需格外注意。
2. **候选 Bean 的选择**
+ 在有多个候选 Bean 可用于注入时该如何选择是一个重要问题。Spring 提供了 `@Primary`, `@Priority` 等注解来辅助决策,但你可能需要考虑其他因素。
3. **自定义类型转换**
+ 如果需要,应确保提供适当的类型转换逻辑,以将 Bean 转换为所需的类型。
4. **性能考虑**
+ 避免不必要的重复查找或计算。在可能的情况下,考虑缓存结果,特别是对于高频率的依赖查找。
5. **生命周期和作用域**
+ 确保考虑到目标 Bean 的生命周期和作用域。例如,一个 prototype 作用域的 Bean 不应该被注入到一个 singleton 作用域的 Bean 中,除非你明确知道这样做的后果。
6. **考虑非常规的依赖源**
+ `resolveDependency` 可能需要考虑来自非常规来源的依赖,如 `FactoryBeans`、`BeanFactory` 或其他特殊的依赖提供者。
### 九、总结
#### 最佳实践总结
#### 源码分析总结
1. **明确环境和配置**
+ 在示例中,使用了 `AnnotationConfigApplicationContext` 作为 Spring 的应用上下文,它基于 Java 注解来配置和初始化 Spring 容器。指定了 `MyConfiguration` 类作为配置源,它用于引导整个应用程序的上下文环境。
2. **简化依赖解析**
+ 通过将依赖解析过程封装到具体的方法中 (`methodResolveDependency` 和 `fieldResolveDependency`),代码的逻辑变得清晰且可维护。
3. **利用Spring的底层API**
+ 虽然大部分时间我们依赖于 Spring 的自动化特性进行依赖注入,但在这个实践中,我们深入地使用了 Spring 的底层 `resolveDependency` 方法来手动解析和注入依赖。这不仅展示了 Spring 的内部工作原理,还提供了当自动注入不适用时的替代解决方案。
4. **手动依赖注入的用例**
+ 即使 `MyServiceB` 不是由 Spring 托管的 Bean我们仍然能够使用 Spring 的机制为它解析和注入所需的依赖。这种能力在某些特定场景下可能非常有用,例如当我们需要将 Spring 与非 Spring 管理的代码集成时。
5. **使用反射增强灵活性**
+ 通过反射API我们能够动态地访问和操作目标对象的方法和字段无论它们是否是公开的。这为我们提供了极大的灵活性特别是当我们需要操作第三方库中的类时。
6. **确保配置的完整性**
+ 确保所需的所有配置资源,如 `application.properties` 文件,都在正确的位置并且被正确加载。在这个示例中,它被用来为 `MyServiceB` 提供一个属性值。
7. **验证和测试**
+ 最后,通过打印方法,确保了所有依赖都已正确解析和注入。在实际应用中,我们应该有相应的单元测试来验证这些行为。
#### 源码分析总结
**解析环境变量**
1. **解析 `@Value` 注解**
+ `doResolveDependency` 方法首先检查是否存在一个建议的值,通常来自 `@Value` 注解。如果找到这样的值,它会首先进行字符串替换(例如替换属性占位符),然后可能对该值进行求值(如果它是一个表达式),最后尝试将该值转换为目标类型。
2. **类型转换**
+ 如果找到了一个建议的值或者已经解析了一个依赖项但其类型与所需的类型不匹配系统会尝试进行类型转换。Spring有一个强大的类型转换系统能够处理各种各样的转换场景。
3. **深入的类型转换**
+ 如果需要进行更复杂的类型转换例如从集合到数组、从字符串到数字等Spring提供了许多内置的转换规则来处理这些场景。
**解析Bean依赖**
1. **依赖解析的起点**
+ `resolveDependency`是Spring的主要方法用于解析bean的依赖关系。
2. **懒加载代理判断**
+ 首先,尝试使用懒加载代理满足依赖关系。如果不能使用懒加载代理,它会进一步尝试解析依赖。
3. **解析具体的依赖**
+ 在`doResolveDependency`中根据依赖的类型Spring可能尝试解析多个Bean候选项如List或Map。它会搜索匹配的Bean并根据条件如类型、qualifiers等选择合适的Bean进行注入。
4. **多值依赖的处理**
+ 如果依赖是多值类型如集合或映射Spring将在`resolveMultipleBeans`中进行处理。
5. **确定注入的Bean**
+ 如果有多个可能的Bean候选项`determineAutowireCandidate`将帮助确定哪一个Bean是最佳的注入选择这可能基于“primary”标记或Bean的优先级。
6. **获取实际的Bean实例**
+ 在所有这些决策之后Spring最终会通过`getBean`方法获取并返回所依赖的Bean实例。

View File

@ -3,6 +3,7 @@ package com.xcs.spring;
import com.xcs.spring.config.MyConfiguration;
import com.xcs.spring.service.MyServiceA;
import com.xcs.spring.service.MyServiceB;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;