Spring 中 @Value 注解实现原理

91 阅读1分钟

使用案例

在 Spring 中可以通过 @Value 注解引用 properties 配置文件中的配置,代码如下:

@RestController
@PropertySource("classpath:hello/hello.properties")
public class TestController {
    @Value("${hello}")
    private String hello;
}

image.png

实现原理

前面的文章 Spring 中@Autowired,@Resource,@Inject 注解实现原理 介绍了 @Autowired@Resource@Inject 注解的实现原理。实际上 @Value 注解修饰的字段的值也是在 AutowiredAnnotationBeanPostProcessorpostProcessProperties() 方法中实现处理的。

首先在 AutowiredAnnotationBeanPostProcessor 的构造函数中初始了要处理 @Value 注解,代码如下:

private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = CollectionUtils.newLinkedHashSet(4);

public AutowiredAnnotationBeanPostProcessor() {
    this.autowiredAnnotationTypes.add(Autowired.class);
    this.autowiredAnnotationTypes.add(Value.class);
}

然后在 AutowiredAnnotationBeanPostProcessorpostProcessProperties() 方法实现找到 @Value 注解修饰的字段,然后给字段赋值的流程,代码如下:

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    } catch (BeanCreationException ex) {
        throw ex;
    } catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

实际上查找 @Value 字段是在 AutowiredAnnotationBeanPostProcessorbuildAutowiringMetadata() 方法中实现的,代码如下:

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }

    final List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> fieldElements = new ArrayList<>();
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            //这里判断字段是否有@Value注解修饰如果有的话则添加到fieldElements中
            MergedAnnotation<?> ann = findAutowiredAnnotation(field);
            if (ann != null) {
                if (Modifier.isStatic(field.getModifiers())) {
                    return;
                }
                boolean required = determineRequiredStatus(ann);
                fieldElements.add(new AutowiredFieldElement(field, required));
            }
        });

        elements.addAll(0, sortMethodElements(methodElements, targetClass));
        elements.addAll(0, fieldElements);
        targetClass = targetClass.getSuperclass();
    } while (targetClass != null && targetClass != Object.class);
    return InjectionMetadata.forElements(elements, clazz);
}

private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
    MergedAnnotations annotations = MergedAnnotations.from(ao);
    //构造函数中初始化的@Value注解就是放到autowiredAnnotationTypes中的
    for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
            MergedAnnotation<?> annotation = annotations.get(type);
            if (annotation.isPresent()) {
                return annotation;
            }
    }
    return null;
}

然后在 postProcessProperties() 中的调用了 InjectionMetadatainject() 方法,然后调用到 AutowiredFieldElementinject() 方法,在它的方法中又会调用到 DefaultListableBeanFactoryresolveDependency() 方法。代码如下:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    value = resolveFieldValue(field, bean, beanName);
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}

@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    desc.setContainingClass(bean.getClass());
    Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
    Assert.state(beanFactory != null, "No BeanFactory available");
    TypeConverter typeConverter = beanFactory.getTypeConverter();
    Object value;
    
    //省略代码
    
    try {
        //调用DefaultListableBeanFactory的resolveDependency()方法
        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    } catch (BeansException ex) {
        throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
    }
}

DefaultListableBeanFactoryresolveDependency() 方法中又实际上会调用到 doResolveDependency() 方法,在该方法中实现了对 @Value 注解字段值的解析。首先从 @Value 注解中获取 value 字段配置的字符串,然后调用解析器将字符串解析为对应的值,然后返回。代码如下:

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        //省略代码
        
        Class<?> type = descriptor.getDependencyType();

        //这里从@Value注解获取注解里面配置的字符串,在上面的案例中就是${hello}这个字符串
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String strValue) {
                //这里将${hello}字符串解析为对应的值
                String resolvedValue = resolveEmbeddedValue(strValue);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                        getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(resolvedValue, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                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()));
            }
        }
    }
}

然后在 AutowiredFieldElementinject() 方法中通过反射的方式将 DefaultListableBeanFactoryresolveDependency() 返回的值设置给字段。代码如下:

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    
    //省略代码
    
    value = resolveFieldValue(field, bean, beanName);
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}