@Value的实现原理

2,972 阅读1分钟

@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());
				}
  1. 先看看@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进去就可以看到。