《Spring6核心技术》第11章:深度解析@Value注解
五、源码解析
5.2 为@Value修饰的属性赋值
本节主要对为@Value修饰的属性赋值的源码流程进行简单的分析,结合源码执行的时序图,会理解的更加深刻,本节的源码执行流程可以结合图11-3~11-4进行理解。具体分析步骤如下所示。
注意:为@Value修饰的属性赋值的源码流程的前半部分与本章5.1节分析源码的流程相同,这里,同样从AbstractAutowireCapableBeanFactory类的doCreateBean()方法开始分析。
(1)解析AbstractAutowireCapableBeanFactory类的doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)。重点关注如下代码片段。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
/************省略其他代码*************/
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
throw bce;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
/************省略其他代码*************/
return exposedObject;
}
可以看到,在AbstractAutowireCapableBeanFactory类的doCreateBean()方法中,会调用populateBean方法为Bean的属性赋值。
(2)解析AbstractAutowireCapableBeanFactory类的populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
/**************省略其他代码*************/
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
/**************省略其他代码*************/
}
可以看到,在populateBean()方法中,会调用InstantiationAwareBeanPostProcessor类的postProcessProperties()方法来处理属性或方法的值。实际上是调用的AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法。
(3)解析AutowiredAnnotationBeanPostProcessor类的postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties(PropertyValues pvs, Object bean, String beanName)。
@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;
}
可以看到,在AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法中,会调用findAutowiringMetadata()方法获取注解的元数据信息。
(4)解析AutowiredAnnotationBeanPostProcessor类的findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs)。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
由于在之前解析并获取@Value修饰的属性的代码流程中,已经完成了对@Value 修饰的属性的获取工作。所以,程序执行到findAutowiringMetadata()方法内部时,injectionMetadataCache缓存中已经有数据了。
(5)返回AutowiredAnnotationBeanPostProcessor类的postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法。在AutowiredAnnotationBeanPostProcessor类的postProcessProperties()方法中,调用了metadata对象的inject()方法为属性赋值。
(6)解析InjectionMetadata类的inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.InjectionMetadata#inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs)。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
可以看到,在InjectionMetadata类的inject()方法中,会循环遍历checkedElements集合,调用遍历出的每个InjectedElement对象的inject()方法为属性赋值。
注意:调用InjectedElement对象的inject()方法时,实际上可能会调用AutowiredFieldElement类的inject()方法、AutowiredMethodElement类的inject()方法或者InjectedElement类的inject()方法。这里,以调用AutowiredFieldElement类的inject()方法为例进行说明。
(7)解析AutowiredFieldElement类的inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
可以看到,在AutowiredFieldElement类的inject()方法中,会调用resolveFieldValue()方法来获取对应的属性值,如下所示。
value = resolveFieldValue(field, bean, beanName);
并通过反射向使用@Value注解标注的字段赋值,如下所示。
field.set(bean, value);
(8)返回AbstractAutowireCapableBeanFactory类的doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法。再来看下源码:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
/************省略其他代码*************/
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
throw bce;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
/************省略其他代码*************/
return exposedObject;
}
可以看到,在AbstractAutowireCapableBeanFactory类的doCreateBean()方法中,为Bean的属性赋值后会调用initializeBean()方法对Bean进行初始化。
(9)解析AbstractAutowireCapableBeanFactory类的initializeBean(String beanName, Object bean, RootBeanDefinition mbd)方法
源码详见:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String beanName, Object bean, RootBeanDefinition mbd)。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
可以看到,在AbstractAutowireCapableBeanFactory类的initializeBean()方法中,会调用applyBeanPostProcessorsBeforeInitialization()方法在初始化之前执行一些逻辑,然后调用invokeInitMethods()执行真正的初始化操作,执行完Bean的初始化,会调用applyBeanPostProcessorsAfterInitialization()方法执行初始化之后的一些逻辑。
至此,为@Value修饰的属性赋值的源码流程分析完毕。
5.3 使用@Value获取属性的值
本节主要对使用@Value获取属性的值的源码流程进行简单的分析,结合源码执行的时序图,会理解的更加深刻,本节的源码执行流程可以结合图11-5~11-7进行理解。具体分析步骤如下所示。
注意:使用@Value获取属性的值的源码流程的前半部分与本章5.2节分析源码的流程相同,这里,从AutowiredFieldElement类的inject()方法开始分析。
(1)解析AutowiredFieldElement类的inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs)。
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
可以看到,在AutowiredFieldElement类的inject()方法中,会调用resolveFieldValue()方法处理获取属性的值。
(2)解析AutowiredFieldElement类的resolveFieldValue(Field field, Object bean, @Nullable String beanName)方法
源码详见:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue(Field field, Object bean, @Nullable String beanName)。
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
/*************省略其他代码************/
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
/*************省略其他代码************/
return value;
}
可以看到,在AutowiredFieldElement类的resolveFieldValue()方法中,会调用beanFactory对象的resolveDependency()方法,继续向下分析。
(3)解析DefaultListableBeanFactory类的resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)
源码详见:org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)。
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
/***************省略其他代码**************/
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
可以看到,在DefaultListableBeanFactory类的resolveDependency()方法中,会调用doResolveDependency()方法进一步处理。
(4)解析DefaultListableBeanFactory类的doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)方法
源码详见:org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter)。
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
/************省略其他代码*************/
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String strValue) {
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()));
}
}
/************省略其他代码*************/
}
可以看到,在DefaultListableBeanFactory类的doResolveDependency()方法中,如果当前获取到的数据是String类型,则调用resolveEmbeddedValue()方法进行处理。
(5)解析AbstractBeanFactory类的resolveEmbeddedValue(@Nullable String value)方法
源码详见:org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue(@Nullable String value)。
@Override
@Nullable
public String resolveEmbeddedValue(@Nullable String value) {
if (value == null) {
return null;
}
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers) {
result = resolver.resolveStringValue(result);
if (result == null) {
return null;
}
}
return result;
}
可以看到,在AbstractBeanFactory类的resolveEmbeddedValue()中,会调用遍历出来的StringValueResolver对象的resolveStringValue()方法进行处理。此时,会进入AbstractEnvironment类的resolvePlaceholders(String text)方法。
(6)解析AbstractEnvironment类的resolvePlaceholders(String text)方法
源码详见:org.springframework.core.env.AbstractEnvironment#resolvePlaceholders(String text)。
@Override
public String resolvePlaceholders(String text) {
return this.propertyResolver.resolvePlaceholders(text);
}
可以看到,在AbstractEnvironment类的resolvePlaceholders()方法中,会调用propertyResolver对象的resolvePlaceholders()方法进行处理。
(7)解析AbstractPropertyResolver类的resolvePlaceholders(String text)方法
源码详见:org.springframework.core.env.AbstractPropertyResolver#resolvePlaceholders(String text)。
@Override
public String resolvePlaceholders(String text) {
if (this.nonStrictHelper == null) {
this.nonStrictHelper = createPlaceholderHelper(true);
}
return doResolvePlaceholders(text, this.nonStrictHelper);
}
可以看到,在AbstractPropertyResolver类的resolvePlaceholders()方法中,会调用doResolvePlaceholders()方法进一步处理。
(8)解析AbstractPropertyResolver类的doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)方法
源码详见:org.springframework.core.env.AbstractPropertyResolver#doResolvePlaceholders(String text, PropertyPlaceholderHelper helper)。
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
可以看到,在AbstractPropertyResolver类的doResolvePlaceholders()方法中,会解析 ${xxx.xxx} 这种占位,最终获取到 key = xxx.xxx,随后根据key去资源文件(xml、application.properties、Environment 等)中查找是否配置了这个key的值。其实是通过调用helper的replacePlaceholders()方法并以Lambda表达式的方式传入getPropertyAsRawString()方法实现的。
(9)解析PropertyPlaceholderHelper类的replacePlaceholders(String value, PlaceholderResolver placeholderResolver)方法
源码详见:org.springframework.util.PropertyPlaceholderHelper#replacePlaceholders(String value, PlaceholderResolver placeholderResolver)。
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, null);
}
可以看到,在PropertyPlaceholderHelper类的replacePlaceholders()方法中,会调用parseStringValue()方法解析String类型的数据。
(10)解析PropertyPlaceholderHelper类的parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable SetvisitedPlaceholders)方法
源码详见:org.springframework.util.PropertyPlaceholderHelper#parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable SetvisitedPlaceholders)。
protected String parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
/***************省略其他代码****************/
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
/**********省略其他代码***********/
}
在PropertyPlaceholderHelper类的parseStringValue()方法中重点关注如下代码片段。
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
会调用placeholderResolver对象的resolvePlaceholder()方法传入解析 ${xxx.xxx} 占位符,获取到的key,其中key的形式为xxx.xxx。调用placeholderResolver对象的resolvePlaceholder()方法会最终调用PropertySourcesPropertyResolver类的getPropertyAsRawString()方法。
(11)解析PropertySourcesPropertyResolver类的getPropertyAsRawString(String key)方法
源码详见:org.springframework.core.env.PropertySourcesPropertyResolver#getPropertyAsRawString(String key)。
@Override
@Nullable
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
可以看到,在getPropertyAsRawString()方法中,会调用getProperty()方法获取属性的值。在调用getPropertyAsRawString()方法时,传入的Key的形式的规则就是:如果使用@Value标注的属性为 ${xxx.xxx} 占位符,则此处传入的Key的形式为xxx.xxx。
(12)解析PropertySourcesPropertyResolver类的getProperty(String key, ClasstargetValueType, boolean resolveNestedPlaceholders)方法
源码详见:org.springframework.core.env.PropertySourcesPropertyResolver#getProperty(String key, ClasstargetValueType, boolean resolveNestedPlaceholders)。
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String string) {
value = resolveNestedPlaceholders(string);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Could not find key '" + key + "' in any property source");
}
return null;
}
在PropertySourcesPropertyResolver类的getProperty()方法中,会从 propertySources 资源中获取 key = xxx.xxx 的值,如果获取到一个对应的值,就会直接返回。其中,在propertySources中会封装PropertiesPropertySource、SystemEnvironmentPropertySource和ResourcePropertySource类型的对象,如图11-8所示。
其中,每种类型的对象中封装的信息如下所示。
- PropertiesPropertySource:封装 JVM 环境变量中的键值对。
- SystemEnvironmentPropertySource:封装操作系统环境变量中的键值对。
- ResourcePropertySource:封装项目中application.properties、yml和xml等文件中的键值对。
通过调试PropertySourcesPropertyResolver类的getProperty()方法,可以发现,ResourcePropertySource对象中获取到对应的值,如图11-9所示。
从ResourcePropertySource对象中获取到对应的值就可以设置到被@Value注解标注的字段上。
至此,使用@Value获取属性的值的源码流程分析完毕。
六、总结
@Value注解介绍完了,我们一起总结下吧!
本章,详细介绍了@Value注解,首先介绍了@Value注解的源码和使用场景,并且对@Value注解的用法进行了简单的介绍。随后,介绍了@Value的使用案例。接下来,从解析并获取 @Value 修饰的属性、为 @Value 修饰属性赋值和使用@Value获取属性值三个方面分别详细介绍了@Value注解在Spring底层执行的源码时序图和源码流程。
七、思考
既然学完了,就开始思考几个问题吧?
关于@Value注解,通常会有如下几个经典面试题:
- @Value注解的作用是什么?
- @Value注解有哪些使用场景?
- @Value向Bean的字段和方法注入值是如何实现的?
- @Value注解在Spring内部的执行流程?
- @Value注解在Spring源码中的执行流程与@Autowired注解有何区别?
- 你在平时工作中,会在哪些场景下使用@Value注解?
- 你从@Value注解的设计中得到了哪些启发?
文章转载自微服务:冰河技术