@ the Value realization

Blog index

Use 1.

In the configuration file application.properties

test.property=hello world
Copy the code

Use in code

@RestController
public class HelloController {

    @Value("${test.property}")
    private String property;
}
Copy the code

2. Source code analysis

In a blog on “the @autowired annotation source” said @ the Value and the realization of the @autowired in AutowiredAnnotationBeanPostProcessor, so we this article specifically to analyze @ Value is how to inject annotation. As usual, annotate the source code first

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {

	/** * The actual value expression such as #{systemProperties.myProp} * or property placeholder such as ${my.app.myProp}. */
	String value(a);

}
Copy the code

Like previous article, execute postProcessMergedBeanDefinition method first, will mark @ Value annotation fields in AutowiredFieldElement object, Then deposit InjectionMetadata object in the next execution postProcessPropertyValues method, finally is AutowiredFieldElement inject method of execution.

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 {
				    // Everything else is the same as @autowired, but the parsing is a little different here
					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 = newShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); }}}else {
							this.cachedFieldValue = null;
						}
						this.cached = true; }}}if(value ! =null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); }}}Copy the code
@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; } // Get the type of field annotated by @value Class<? > type = descriptor.getDependencyType(); // Get the tagged content, ${test. Property} Object Value = ${test. Property} Object Value = ${test getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value ! = null) {if (value instanceof String) {// Replace ${test.property} with the value String strVal = resolveEmbeddedValue((String) value) in the configuration file; BeanDefinition bd = (beanName ! = null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } // Get the converter TypeConverter converter = (TypeConverter! = null ? typeConverter : getTypeConverter()); Try {/ / type converter to convert the result to the corresponding return the converter. The convertIfNecessary (value, type, descriptor. GetTypeDescriptor ()); }Copy the code
  1. Let’s look at the @Value call stack

Then came to the 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) {
	    // Replace ${test.property} with the value in the configuration file
		result = resolver.resolveStringValue(result);
		if (result == null) {
			return null; }}return result;
}

Copy the code

Specific parsing ${} XXX parsed into specific values, are interested can go to see the class PropertySourcesPlaceholderConfigurer, namely resolver. ResolveStringValue (result) debug in can see this line of code.