优化@Value注解
parent
28f6dcfd93
commit
a66a8f2d29
|
@ -69,8 +69,8 @@ public @interface Value {
|
|||
1. **提供属性注入**
|
||||
+ 允许从不同的配置源(如属性文件、系统属性等)直接向 Spring 管理的 beans 中注入值。
|
||||
2. **支持表达式**:
|
||||
- **SpEL (Spring Expression Language) 表达式**:例如,`#{systemProperties.myProp}` 可以从系统属性中获取名为 `myProp` 的值。
|
||||
- **属性占位符**:例如,`${my.app.myProp}` 可以从预定义的配置源,如 `application.properties` 或 `application.yml` 文件,获取名为 `my.app.myProp` 的属性值。
|
||||
- SpEL (Spring Expression Language) 表达式:例如,`#{systemProperties.myProp}` 可以从系统属性中获取名为 `myProp` 的值。
|
||||
- 属性占位符:例如,`${my.app.myProp}` 可以从预定义的配置源,如 `application.properties` 或 `application.yml` 文件,获取名为 `my.app.myProp` 的属性值。
|
||||
3. **动态值解析**
|
||||
+ 与只能在启动时设置静态值相比,`@Value` 注解可以解析动态表达式,从而为字段或构造函数参数提供动态值。
|
||||
4. **用于字段、方法参数、构造函数参数和注解**
|
||||
|
@ -338,7 +338,6 @@ private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
|
|||
|
||||
```java
|
||||
public AutowiredAnnotationBeanPostProcessor() {
|
||||
this.autowiredAnnotationTypes.add(Autowired.class);
|
||||
this.autowiredAnnotationTypes.add(Value.class);
|
||||
// ... [代码部分省略以简化]
|
||||
}
|
||||
|
@ -399,11 +398,11 @@ public void inject(Object target, @Nullable String beanName, @Nullable PropertyV
|
|||
```java
|
||||
@Override
|
||||
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
|
||||
// 获取代表带有@Autowired注解的字段的Field对象。
|
||||
// 步骤1. 获取代表带有@Autowired注解的字段的Field对象。
|
||||
Field field = (Field) this.member;
|
||||
|
||||
Object value;
|
||||
// 如果字段的值已经被缓存(即先前已解析过),则尝试从缓存中获取。
|
||||
// 步骤2. 如果字段的值已经被缓存(即先前已解析过),则尝试从缓存中获取。
|
||||
if (this.cached) {
|
||||
try {
|
||||
// 从缓存中获取已解析的字段值。
|
||||
|
@ -415,21 +414,21 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
|
|||
}
|
||||
}
|
||||
else {
|
||||
// 如果字段值未被缓存,直接解析。
|
||||
// 步骤3. 如果字段值未被缓存,直接解析。
|
||||
value = resolveFieldValue(field, bean, beanName);
|
||||
}
|
||||
|
||||
// 如果解析到的值不为null...
|
||||
// 步骤4. 如果解析到的值不为null...
|
||||
if (value != null) {
|
||||
// 使字段可访问,这是必要的,特别是当字段是private时。
|
||||
// 步骤4.1. 使字段可访问,这是必要的,特别是当字段是private时。
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
// 实际将解析的值注入到目标bean的字段中。
|
||||
// 步骤4.2. 实际将解析的值注入到目标bean的字段中。
|
||||
field.set(bean, value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在`org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue`方法中,通过`beanFactory.resolveDependency`方法从Spring的bean工厂中解析字段的值。
|
||||
首先来到`org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject`方法中的步骤3。在`org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue`方法中,通过`beanFactory.resolveDependency`方法从Spring的bean工厂中解析字段的值。
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
|
@ -448,6 +447,379 @@ private Object resolveFieldValue(Field field, Object bean, @Nullable String bean
|
|||
}
|
||||
```
|
||||
|
||||
在`org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency`方法中,首先尝试获取一个延迟解析代理。如果无法获得,它会进一步尝试解析依赖。`doResolveDependency` 是实际进行解析工作的方法。
|
||||
|
||||
```java
|
||||
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`方法中,首先从`DependencyDescriptor`获取注解值,然后处理其中的字符串属性占位符和SpEL表达式。最后,确保值根据目标字段或参数类型进行正确的类型转换,并将其注入相应的位置。
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
|
||||
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
|
||||
|
||||
// ... [其他代码部分省略以简化]
|
||||
|
||||
try {
|
||||
// 尝试快速解析依赖
|
||||
Object shortcut = descriptor.resolveShortcut(this);
|
||||
if (shortcut != null) {
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
// 获取依赖的类型
|
||||
Class<?> type = descriptor.getDependencyType();
|
||||
|
||||
// 步骤1. 获取依赖的建议值,例如@Value注解的值
|
||||
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
|
||||
|
||||
// 如果建议的值是字符串类型
|
||||
if (value instanceof String) {
|
||||
// 步骤2. 解析嵌入的值,如处理属性占位符
|
||||
String strVal = resolveEmbeddedValue((String) value);
|
||||
|
||||
// 获取与bean名称相关的BeanDefinition
|
||||
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
|
||||
getMergedBeanDefinition(beanName) : null);
|
||||
|
||||
// 步骤3. 对Bean定义字符串进行评估,如处理SpEL表达式
|
||||
value = evaluateBeanDefinitionString(strVal, bd);
|
||||
}
|
||||
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
try {
|
||||
// 步骤4. 获取类型转换器并进行必要的类型转换
|
||||
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
|
||||
}
|
||||
catch (UnsupportedOperationException ex) {
|
||||
// ... [其他代码部分省略以简化]
|
||||
}
|
||||
|
||||
// ... [其他代码部分省略以简化]
|
||||
|
||||
}
|
||||
// ... [其他代码部分省略以简化]
|
||||
}
|
||||
```
|
||||
|
||||
首先来到在`org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency`方法中的步骤1。在`org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#getSuggestedValue`方法中,主要是用于解析与`DependencyDescriptor`相关的注解值,特别是`@Value`注解。如果字段或方法参数上有`@Value`注解,它会从注解中提取相应的值或表达式。
|
||||
|
||||
```java
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getSuggestedValue(DependencyDescriptor descriptor) {
|
||||
// 从描述符的注解中查找@Value注解提供的值
|
||||
Object value = findValue(descriptor.getAnnotations());
|
||||
|
||||
// 如果在描述符的注解中没有找到,检查是否存在与此描述符关联的方法参数
|
||||
if (value == null) {
|
||||
MethodParameter methodParam = descriptor.getMethodParameter();
|
||||
|
||||
if (methodParam != null) {
|
||||
// 如果存在方法参数,再从方法参数的注解中查找@Value提供的值
|
||||
value = findValue(methodParam.getMethodAnnotations());
|
||||
}
|
||||
}
|
||||
// 返回找到的值,如果没有找到则返回null
|
||||
return value;
|
||||
}
|
||||
```
|
||||
|
||||
在`org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#findValue`方法中,目标是在提供的注解集合中找到并返回`@Value`注解的值。如果没有找到,它会返回null。
|
||||
|
||||
```java
|
||||
protected Object findValue(Annotation[] annotationsToSearch) {
|
||||
if (annotationsToSearch.length > 0) { // qualifier annotations have to be local
|
||||
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
|
||||
if (attr != null) {
|
||||
return extractValue(attr);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
在`org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#extractValue`方法中,目的是从`AnnotationAttributes`对象中直接提取`@Value`注解的值。如果没有提供值,它会抛出异常。
|
||||
|
||||
```java
|
||||
protected Object extractValue(AnnotationAttributes attr) {
|
||||
Object value = attr.get(AnnotationUtils.VALUE);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Value annotation must have a value attribute");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
```
|
||||
|
||||
当我们使用 `@Value("${app.description:我是默认值}")` 在你的字段上时,Spring 会在运行时尝试解析这个属性占位符。当 Spring 容器处理这个字段的注入时,它会使用 `QualifierAnnotationAutowireCandidateResolver`(或其他相关的后处理器)来获取并解析这个属性值。在我们的最佳实践下,`extractValue` 方法就是从注解属性中提取该属性占位符的逻辑,即返回值为 `"${app.description:我是默认值}"`。这个值随后会被 Spring 的属性解析器进一步处理,解析真实的值或使用默认值,并最终注入到 `appDescription` 字段中。
|
||||
|
||||
```java
|
||||
${app.description:我是默认值}
|
||||
```
|
||||
|
||||
然后我们来到在`org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency`方法中的步骤2。在`org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue`方法中,用于解析给定字符串中的内嵌值。它遍历所有注册的`StringValueResolver`解析器,对给定的字符串值进行连续解析,以处理可能存在的多重内嵌值或引用。例如,如果字符串中有一个`${property}`形式的属性,它可以通过注册的解析器进行处理和解析为实际的属性值。
|
||||
|
||||
```java
|
||||
@Override
|
||||
@Nullable
|
||||
public String resolveEmbeddedValue(@Nullable String value) {
|
||||
// 初始检查:如果提供的值为null,则直接返回null
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String result = value;
|
||||
|
||||
// 遍历所有的内嵌值解析器
|
||||
for (StringValueResolver resolver : this.embeddedValueResolvers) {
|
||||
// 使用当前解析器解析result中的值
|
||||
result = resolver.resolveStringValue(result);
|
||||
|
||||
// 如果解析后的值为null,则直接返回null
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 返回所有解析器处理后的最终值
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
然后我们来到在`org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency`方法中的步骤3。在`org.springframework.beans.factory.support.AbstractBeanFactory#evaluateBeanDefinitionString`方法中,用于评估给定的字符串值,特别是处理可能包含Spring表达式语言 (SpEL) 表达式的字符串。首先,它检查是否有一个`beanExpressionResolver`可用来解析SpEL。如果有,它可能会获取bean定义的作用域(如果提供了bean定义),然后使用`beanExpressionResolver`对字符串值进行评估,并考虑到相关的作用域上下文。
|
||||
|
||||
```java
|
||||
@Nullable
|
||||
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
|
||||
// 如果没有设置bean表达式解析器,直接返回原始值
|
||||
if (this.beanExpressionResolver == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Scope scope = null;
|
||||
|
||||
// 如果提供了bean定义
|
||||
if (beanDefinition != null) {
|
||||
// 获取bean的作用域
|
||||
String scopeName = beanDefinition.getScope();
|
||||
|
||||
// 如果作用域名称不为空,则尝试从已注册的作用域中获取对应的作用域
|
||||
if (scopeName != null) {
|
||||
scope = getRegisteredScope(scopeName);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用bean表达式解析器解析提供的值,并返回结果
|
||||
// 这可以处理例如使用Spring EL的情况
|
||||
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
|
||||
}
|
||||
```
|
||||
|
||||
在`org.springframework.context.expression.StandardBeanExpressionResolver#evaluate`方法中,主要目的是解析并评估给定的值(可能是一个Spring EL表达式)。为了提高性能,它使用缓存来存储先前解析的表达式和评估上下文。此方法首先从缓存中检索或解析表达式,然后准备一个评估上下文,并使用它评估表达式。这个评估上下文被配置为能够访问与Spring容器相关的各种内容,如beans、环境属性等。
|
||||
|
||||
```java
|
||||
@Override
|
||||
@Nullable
|
||||
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException {
|
||||
// 如果提供的值为空或没有内容,直接返回该值
|
||||
if (!StringUtils.hasLength(value)) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
// 从缓存中尝试获取表达式
|
||||
Expression expr = this.expressionCache.get(value);
|
||||
// 如果缓存中没有表达式,则使用表达式解析器解析该值,并将其放入缓存中
|
||||
if (expr == null) {
|
||||
expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext);
|
||||
this.expressionCache.put(value, expr);
|
||||
}
|
||||
|
||||
// 尝试从缓存中获取评估上下文
|
||||
StandardEvaluationContext sec = this.evaluationCache.get(evalContext);
|
||||
// 如果缓存中没有评估上下文,则创建一个新的,并进行一些初始化配置
|
||||
if (sec == null) {
|
||||
sec = new StandardEvaluationContext(evalContext);
|
||||
// 添加各种属性访问器以支持对特定类型的属性的访问
|
||||
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
|
||||
sec.addPropertyAccessor(new BeanFactoryAccessor());
|
||||
sec.addPropertyAccessor(new MapAccessor());
|
||||
sec.addPropertyAccessor(new EnvironmentAccessor());
|
||||
// 设置bean解析器和类型定位器
|
||||
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
|
||||
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
|
||||
// 如果有可用的转换服务,则设置类型转换器
|
||||
ConversionService conversionService = evalContext.getBeanFactory().getConversionService();
|
||||
if (conversionService != null) {
|
||||
sec.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
}
|
||||
// 自定义评估上下文,允许子类提供额外的配置
|
||||
customizeEvaluationContext(sec);
|
||||
// 将创建的评估上下文放入缓存
|
||||
this.evaluationCache.put(evalContext, sec);
|
||||
}
|
||||
|
||||
// 使用已准备好的评估上下文评估表达式并返回结果
|
||||
return expr.getValue(sec);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// 如果在解析或评估过程中出现任何异常,抛出BeanExpressionException
|
||||
throw new BeanExpressionException("Expression parsing failed", ex);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
然后我们来到在`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 {
|
||||
Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
|
||||
|
||||
try {
|
||||
// 委托给typeConverterDelegate进行实际的转换工作
|
||||
return this.typeConverterDelegate.convertIfNecessary(null, null, value, requiredType, typeDescriptor);
|
||||
}
|
||||
catch (ConverterNotFoundException | IllegalStateException ex) {
|
||||
throw new ConversionNotSupportedException(value, requiredType, ex);
|
||||
}
|
||||
catch (ConversionException | IllegalArgumentException ex) {
|
||||
throw new TypeMismatchException(value, requiredType, ex);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在`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);
|
||||
|
||||
// 用于捕获ConversionService尝试失败的异常
|
||||
ConversionFailedException conversionAttemptEx = null;
|
||||
|
||||
// 没有自定义编辑器,但是否指定了自定义ConversionService?
|
||||
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
|
||||
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
|
||||
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
|
||||
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
|
||||
try {
|
||||
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
|
||||
}
|
||||
catch (ConversionFailedException ex) {
|
||||
conversionAttemptEx = ex; // 记录转换尝试失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object convertedValue = newValue;
|
||||
|
||||
// 如果值不是所需类型,进行转换
|
||||
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
|
||||
if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
|
||||
convertedValue instanceof String) {
|
||||
TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
|
||||
if (elementTypeDesc != null) {
|
||||
Class<?> elementType = elementTypeDesc.getType();
|
||||
if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
|
||||
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (editor == null) {
|
||||
editor = findDefaultEditor(requiredType); // 如果没有自定义编辑器,找默认的
|
||||
}
|
||||
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor); // 进行转换
|
||||
}
|
||||
|
||||
// 对于特定情况尝试标准类型转换,如字符串到枚举、数字转换等
|
||||
boolean standardConversion = false;
|
||||
if (requiredType != null) {
|
||||
if (convertedValue != null) {
|
||||
// 若目标类型为Object,则直接返回转换值
|
||||
if (Object.class == requiredType) {
|
||||
return (T) convertedValue;
|
||||
}
|
||||
// 若目标类型为数组,进行数组转换
|
||||
else if (requiredType.isArray()) {
|
||||
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
|
||||
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
|
||||
}
|
||||
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
|
||||
}
|
||||
// 如果是Collection或Map,则尝试转换集合或映射的内容
|
||||
else if (convertedValue instanceof Collection) {
|
||||
convertedValue = convertToTypedCollection((Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
|
||||
standardConversion = true;
|
||||
}
|
||||
else if (convertedValue instanceof Map) {
|
||||
convertedValue = convertToTypedMap((Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
|
||||
standardConversion = true;
|
||||
}
|
||||
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
|
||||
convertedValue = Array.get(convertedValue, 0);
|
||||
standardConversion = true;
|
||||
}
|
||||
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
|
||||
return (T) convertedValue.toString();
|
||||
}
|
||||
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
|
||||
String trimmedValue = ((String) convertedValue).trim();
|
||||
if (requiredType.isEnum() && trimmedValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
|
||||
standardConversion = true;
|
||||
}
|
||||
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
|
||||
convertedValue = NumberUtils.convertNumberToTargetClass((Number) convertedValue, (Class<Number>) requiredType);
|
||||
standardConversion = true;
|
||||
}
|
||||
}
|
||||
else if (requiredType == Optional.class) {
|
||||
convertedValue = Optional.empty();
|
||||
}
|
||||
|
||||
// 如果经过上述所有转换后,值仍不匹配目标类型,则抛出异常
|
||||
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
|
||||
if (conversionAttemptEx != null) {
|
||||
throw conversionAttemptEx;
|
||||
}
|
||||
else if (conversionService != null && typeDescriptor != null) {
|
||||
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
|
||||
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
|
||||
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("转换失败"); // 实际异常消息会更详细,这里简化了
|
||||
}
|
||||
}
|
||||
|
||||
if (conversionAttemptEx != null) {
|
||||
throw conversionAttemptEx;
|
||||
}
|
||||
|
||||
return (T) convertedValue;
|
||||
}
|
||||
```
|
||||
|
||||
### 八、注意事项
|
||||
|
||||
1. **SpEL表达式**
|
||||
|
@ -495,10 +867,12 @@ private Object resolveFieldValue(Field field, Object bean, @Nullable String bean
|
|||
1. **核心后处理器**:
|
||||
+ `AutowiredAnnotationBeanPostProcessor`是处理`@Value`等注解的主要后处理器。它实现了两个关键的接口,`MergedBeanDefinitionPostProcessor`和`InstantiationAwareBeanPostProcessor`,这两个接口允许在bean的生命周期中的关键阶段进行干预,为属性注入提供了机制。
|
||||
2. **收集阶段**:
|
||||
+ 在`postProcessMergedBeanDefinition`方法中,后处理器确保给定的bean定义与预期的自动装配元数据一致。主要任务是为给定的bean名称和类型查找相关的`InjectionMetadata`,这可能包含了该bean的字段和方法的注入信息。
|
||||
- 在`postProcessMergedBeanDefinition`方法中,`AutowiredAnnotationBeanPostProcessor`确保bean的定义与预期的自动装配元数据匹配。
|
||||
- `findAutowiringMetadata`方法确保为给定的bean名称和类获取相关的`InjectionMetadata`,并利用缓存机制优化性能。
|
||||
- `buildAutowiringMetadata`方法检查类及其所有父类,确定带有`@Autowired`、`@Value`等注解的字段和方法,并为这些元素创建一个统一的`InjectionMetadata`对象。
|
||||
3. **注入阶段**:
|
||||
+ 在`postProcessProperties`方法中,后处理器处理bean属性的注入,特别是通过`@Value`进行的注入。具体来说,它会获取与bean名称和类相关的`InjectionMetadata`,然后使用这些元数据来注入属性。
|
||||
4. **字段注入**:
|
||||
+ 在`AutowiredFieldElement#inject`方法中,首先会检查字段的值是否已经被缓存。如果已缓存,则从缓存中获取,否则重新解析。然后将解析的值注入到目标bean的字段中。
|
||||
5. **值解析**:
|
||||
+ 在`AutowiredFieldElement#resolveFieldValue`方法中,后处理器从Spring的bean工厂中解析字段的值。它主要通过`beanFactory.resolveDependency`方法来完成这一工作。
|
||||
+ `postProcessProperties`方法用于处理bean的属性的后处理,特别是注入由`@Value`等注解标记的属性。
|
||||
+ `InjectionMetadata#inject`方法用于将所有需要注入的元素(例如带有`@Value`的字段)注入到目标bean中。
|
||||
+ `AutowiredFieldElement#inject`方法处理具体的字段注入,包括解析`@Value`注解中的值。
|
||||
+ `DefaultListableBeanFactory#resolveDependency`方法从Spring的bean工厂中解析字段的值。
|
||||
+ `DefaultListableBeanFactory#doResolveDependency`方法是实际解析工作的主要场所,涉及到处理`@Value`注解中的字符串属性占位符和SpEL表达式,并确保值经过正确的类型转换。
|
Loading…
Reference in New Issue