Spring 中 @Value 注解实现原理
使用案例
在 Spring 中可以通过 @Value
注解引用 properties 配置文件中的配置,代码如下:
@RestController
@PropertySource("classpath:hello/hello.properties")
public class TestController {@Value("${hello}")private String hello;
}
实现原理
前面的文章 Spring 中@Autowired,@Resource,@Inject 注解实现原理 介绍了 @Autowired
,@Resource
,@Inject
注解的实现原理。实际上 @Value
注解修饰的字段的值也是在 AutowiredAnnotationBeanPostProcessor
的 postProcessProperties()
方法中实现处理的。
首先在 AutowiredAnnotationBeanPostProcessor
的构造函数中初始了要处理 @Value
注解,代码如下:
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = CollectionUtils.newLinkedHashSet(4);public AutowiredAnnotationBeanPostProcessor() {this.autowiredAnnotationTypes.add(Autowired.class);this.autowiredAnnotationTypes.add(Value.class);
}
然后在 AutowiredAnnotationBeanPostProcessor
的 postProcessProperties()
方法实现找到 @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
字段是在 AutowiredAnnotationBeanPostProcessor
的 buildAutowiringMetadata()
方法中实现的,代码如下:
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()
中的调用了 InjectionMetadata
的 inject()
方法,然后调用到 AutowiredFieldElement
的 inject()
方法,在它的方法中又会调用到 DefaultListableBeanFactory
的 resolveDependency()
方法。代码如下:
@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);}
}
在 DefaultListableBeanFactory
的 resolveDependency()
方法中又实际上会调用到 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()));}}}
}
然后在 AutowiredFieldElement
的 inject()
方法中通过反射的方式将 DefaultListableBeanFactory
的 resolveDependency()
返回的值设置给字段。代码如下:
@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);}
}