使用案例
在 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);
}
}