@ 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
- 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.