@Value实现
1. 用法
在配置文件application.properties
中配置
test.property=hello world
代码中使用
@RestController
public class HelloController {
@Value("${test.property}")
private String property;
}
2. 源码分析
在上一篇博客《@Autowired注解源码》说过@Value
与@Autowired
的实现都在AutowiredAnnotationBeanPostProcessor
中,那么我们这篇专门来分析@Value
注解是如何注入的。
老样子,先注解源码
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
/**
* The actual value expression such as <code>#{systemProperties.myProp}</code>
* or property placeholder such as <code>${my.app.myProp}</code>.
*/
String value();
}
跟上篇文章一样,先执行 postProcessMergedBeanDefinition方法,将标注@Value
注解的字段封装成AutowiredFieldElement
对象,然后存入InjectionMetadata对象中
接下来执行postProcessPropertyValues 方法,最终执行的是AutowiredFieldElement的inject方法。
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 其他地方都是与@autowired一样,只是这里的解析有点差异
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 获取被@Value标注的字段的类型
Class<?> type = descriptor.getDependencyType();
// 获取被标注的内容,比如这里是 @Value("${test.property}"),那么value解析出来的是${test.property}
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 核心代码:将${test.property}替换成配置文件中的值
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
// 获取转换器
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 使用转换器将结果转换成对应的类型
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
- 先看看@Value的调用栈
然后来到org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue
public String resolveEmbeddedValue(@Nullable String value) {
if (value == null) {
return null;
}
String result = value;// ${test.property}
for (StringValueResolver resolver : this.embeddedValueResolvers) {
// 将${test.property}替换为配置文件中的值
result = resolver.resolveStringValue(result);
if (result == null) {
return null;
}
}
return result;
}
具体解析${xxx}解析成具体值,有兴趣可以去看这个类PropertySourcesPlaceholderConfigurer
,也就是resolver.resolveStringValue(result)
这行代码debug进去就可以看到。