喜欢Spring源码的朋友,点点关注,您的支持是我前进的动力。
对@value属性赋值是发生在bean属性填充阶段,也就是populateBean方法。
下面是相关代码的时序图:
具体代码定位到
DefaultListableBeanFactory类的doResolveDependency方法:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Class<?> type = descriptor.getDependencyType();
//获得@Value注解的value值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
//解析value值,并且从MutablePropertySources中获取属性值
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
......
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
getSuggestedValue是获得@Value注解的value值,例如我们在某个类里面定义了cc属性
@Value("${test.cc}")
private String cc;
getSuggestedValue获取到值是${test.cc}。
resolveEmbeddedValue方法是从MutablePropertySources中获取到属性值.
我们看下resolveEmbeddedValue方法是如何获取到属性值的。
@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;
}
embeddedValueResolvers是CopyOnWriteArrayList类型,我们期望的resolver是从environment中的MutablePropertySources获取到配置项的值。
我们通过idea,看到StringValueResolver的实现类有
PlaceholderResolvingStringValueResolver,StaticStringValueResolver,EmbeddedValueResolver,这几个实现类的resolveStringValue都没有从MutablePropertySources取值,这里的StringValueResolver真正的实现类在哪里呢?这个问题困惑了我好久,下面我们一起看下真正的实现类在哪里
众里寻她千百度,蓦然回首....
在idea中查找embeddedValueResolvers的Usages,找到了
PropertySourcesPlaceholderConfigurer类,它是BeanFactoryPostProcessor的实现类。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//....省略前面的代码
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
postProcessBeanFactory方法中调用了processProperties方法,点进方法查看一下,关键点就在里面
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
final ConfigurablePropertyResolver propertyResolver) throws BeansException {
propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);
propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
propertyResolver.setValueSeparator(this.valueSeparator);
//创建了匿名的StringValueResolver的实现类,这才是获取@Value值的处理类
StringValueResolver valueResolver = strVal -> {
String resolved = (this.ignoreUnresolvablePlaceholders ?
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal));
if (this.trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(this.nullValue) ? null : resolved);
};
doProcessProperties(beanFactoryToProcess, valueResolver);
}
在上面的方法内部创建了匿名的StringValueResolver的实现类,实现了resolveStringValue方法,doProcessProperties方法会将StringValueResolver对象加入到embeddedValueResolvers中去。
匿名的StringValueResolver的实现类的resolveStringValue方法调用的是 PropertySourcesPropertyResolver类的处理方法,参数是MutablePropertySources类型的,内容包含了apollo配置,环境变量,项目内的properties文件,yml文件等配置。
一言以蔽之,真正获取属性值的类是PropertySourcesPropertyResolver。
如何从MutablePropertySources中获取某个配置项的?
具体处理在
PropertySourcesPropertyResolver类的getPropertyAsRawString方法
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
@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) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Could not find key '" + key + "' in any property source");
}
return null;
}
getProperty方法会对propertySources进行循环,获取到值,就退出循环。
比如说在apollo和application.properties文件中都存在相同的配置项test.cc,但是值不同,由于apollo配置是放在List的最前面,所以会取apollo里面的值,application.properties内的值会被忽略掉。这就是配置优先级的体现。
总结不易,请关注点赞哦!!!
\