BeanDefinition占位符属性解析
我们可以使用占位符去从设置Bean的属性值,可以使用context:property-placeholder标签来指定我们需要使用到的配置文件,Spring解析BeanDefinition的占位符格式的属性,会从配置文件中去查找对应的值替换调原本的占位符。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="false">
<context:component-scan base-package="demo"/>
<context:property-placeholder location="classpath:application.properties"/>
<bean id="zhangSan" class="demo.ZhangSan">
<property name="name" value="${name}"/>
</bean>
</beans>
自定义标签前面解析过了,这里快速过一下,首先来看到context:property-placeholder标签解析的代码
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
//直接看PropertyPlaceholderBeanDefinitionParser类
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
private static final String SYSTEM_PROPERTIES_MODE_ATTRIBUTE = "system-properties-mode";
private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";
@Override
@SuppressWarnings("deprecation")
protected Class<?> getBeanClass(Element element) {
// As of Spring 3.1, the default value of system-properties-mode has changed from
// 'FALLBACK' to 'ENVIRONMENT'. This latter value indicates that resolution of
// placeholders against system properties is a function of the Environment and
// its current set of PropertySources.
//父类parse方法会调用这里,把PropertySourcesPlaceholderConfigurer类变成beanDefinition注册到容器中
if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) {
return PropertySourcesPlaceholderConfigurer.class;
}
// The user has explicitly specified a value for system-properties-mode: revert to
// PropertyPlaceholderConfigurer to ensure backward compatibility with 3.0 and earlier.
// This is deprecated; to be removed along with PropertyPlaceholderConfigurer itself.
return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//获取标签中的值封装到beanDefinition中(比如location属性)
super.doParse(element, parserContext, builder);
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE);
if (StringUtils.hasLength(systemPropertiesModeName) &&
!systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);
}
if (element.hasAttribute("value-separator")) {
builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
}
if (element.hasAttribute("trim-values")) {
builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
}
if (element.hasAttribute("null-value")) {
builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
}
}
}
现在来看PropertySourcesPlaceholderConfigurer类
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";
@Nullable
private MutablePropertySources propertySources;
@Nullable
private PropertySources appliedPropertySources;
@Nullable
private Environment environment;
public void setPropertySources(PropertySources propertySources) {
this.propertySources = new MutablePropertySources(propertySources);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
//父类实现了BeanFactoryPostProcessor接口,子类重写父类的postProcessBeanFactory
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//这里把environment添加到propertySources中,
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(
new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
@Nullable
//AbstractEnvironment对象实现PropertyResolver接口
public String getProperty(String key) {
//从environment中的propertyResolver对象中获取值
return this.source.getProperty(key);
}
}
);
}
//这里把localPropertySource(配置文件配置的key value)添加到propertySources中,
//mergeProperties()返回配置文件中配置的数据
try {
PropertySource<?> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
//默认false
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
//添加到environment的后面,先从environment中找,再去配置文件找
else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
//看这里
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
final ConfigurablePropertyResolver propertyResolver) throws BeansException {
//默认"${"
propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);
//默认"}"
propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
//默认":" (${name:spring}) propertySources中找不到name对应的值时默认name为spring
propertyResolver.setValueSeparator(this.valueSeparator);
//占位符解析器
StringValueResolver valueResolver = strVal -> {
//ignoreUnresolvablePlaceholders 默认为false
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);
}
@Override
@Deprecated
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) {
throw new UnsupportedOperationException(
"Call processProperties(ConfigurableListableBeanFactory, ConfigurablePropertyResolver) instead");
}
public PropertySources getAppliedPropertySources() throws IllegalStateException {
Assert.state(this.appliedPropertySources != null, "PropertySources have not yet been applied");
return this.appliedPropertySources;
}
}
protected Properties mergeProperties() throws IOException {
Properties result = new Properties();
//默认false
if (this.localOverride) {
// Load properties from file upfront, to let local properties override.
loadProperties(result);
}
if (this.localProperties != null) {
for (Properties localProp : this.localProperties) {
CollectionUtils.mergePropertiesIntoMap(localProp, result);
}
}
//加载配置文件封装到result中返回
if (!this.localOverride) {
// Load properties from file afterwards, to let those properties override.
loadProperties(result);
}
return result;
}
protected void loadProperties(Properties props) throws IOException {
if (this.locations != null) {
//循环所有的配置文件
for (Resource location : this.locations) {
if (logger.isTraceEnabled()) {
logger.trace("Loading properties file from " + location);
}
try {
//加载配置文件封装到props
PropertiesLoaderUtils.fillProperties(
props, new EncodedResource(location, this.fileEncoding), this.propertiesPersister);
}
catch (FileNotFoundException | UnknownHostException ex) {
if (this.ignoreResourceNotFound) {
if (logger.isDebugEnabled()) {
logger.debug("Properties resource not found: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
}
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
//获取所有BeanDefinition的beanName
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
//循环解析占位符
for (String curName : beanNames) {
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
//看这里
visitor.visitBeanDefinition(bd);
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}
// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
//@Value的占位符解析器valueResolver
//往beanFactory中的embeddedValueResolvers添加valueResolver
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
public void visitBeanDefinition(BeanDefinition beanDefinition) {
//解析BeanDefinition的占位符属性
//调用占位符解析方法解析占位符
//解析获得的值替换掉原本占位符的值
visitParentName(beanDefinition);
visitBeanClassName(beanDefinition);
visitFactoryBeanName(beanDefinition);
visitFactoryMethodName(beanDefinition);
visitScope(beanDefinition);
if (beanDefinition.hasPropertyValues()) {
visitPropertyValues(beanDefinition.getPropertyValues());
}
if (beanDefinition.hasConstructorArgumentValues()) {
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
visitIndexedArgumentValues(cas.getIndexedArgumentValues());
visitGenericArgumentValues(cas.getGenericArgumentValues());
}
}
protected Object resolveValue(@Nullable Object value) {
if (value instanceof BeanDefinition) {
visitBeanDefinition((BeanDefinition) value);
}
else if (value instanceof BeanDefinitionHolder) {
visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
}
else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (newBeanName == null) {
return null;
}
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanReference(newBeanName);
}
}
else if (value instanceof RuntimeBeanNameReference) {
RuntimeBeanNameReference ref = (RuntimeBeanNameReference) value;
String newBeanName = resolveStringValue(ref.getBeanName());
if (newBeanName == null) {
return null;
}
if (!newBeanName.equals(ref.getBeanName())) {
return new RuntimeBeanNameReference(newBeanName);
}
}
else if (value instanceof Object[]) {
visitArray((Object[]) value);
}
else if (value instanceof List) {
visitList((List) value);
}
else if (value instanceof Set) {
visitSet((Set) value);
}
else if (value instanceof Map) {
visitMap((Map) value);
}
//讲解标签解析的时候分析过了BeanDefinition的生成
//bean标签property属性的没有配置ref时,而是配置了value时
//value的值被包装为TypedStringValue类型封装在BeanDefinition中(BeanDefinitionParserDelegate类的parsePropertyValue方法)
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
String stringValue = typedStringValue.getValue();
if (stringValue != null) {
//调用占位符解析方法resolveRequiredPlaceholders解析占位符
String visitedString = resolveStringValue(stringValue);
typedStringValue.setValue(visitedString);
}
}
else if (value instanceof String) {
return resolveStringValue((String) value);
}
return value;
}
看到占位符解析方法resolveRequiredPlaceholders
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
//以${开头
int startIndex = value.indexOf(this.placeholderPrefix);
if (startIndex == -1) {
return value;
}
StringBuilder result = new StringBuilder(value);
//while循环 递归调用resolvePlaceholder 可能占位符嵌套 ${${}}
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
//去除${}
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (visitedPlaceholders == null) {
visitedPlaceholders = new HashSet<>(4);
}
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
//调用占位符解析方法(resolvePlaceholders)从propertySources获取值
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());
//调用占位符解析方法(resolvePlaceholders)从propertySources获取值
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
//propertySgaizhiources获取不到值
if (propVal == null) {
//赋值为默认值
propVal = defaultValue;
}
}
}
//没有冒号直接取到值
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}
看到占位符解析方法resolvePlaceholders
@Override
@Nullable
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) {
//循环从propertySources取值
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
//使用占位符作为key获取值
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.isTraceEnabled()) {
logger.trace("Could not find key '" + key + "' in any property source");
}
return null;
}
@Value占位符属性解析
接着我们来看@Value的值,如何依赖注入到bean中,之前已经讲过@Value的注解收集,现在来看解析过程。直接看到AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,处理bean依赖注入的值的代码。之前讲实例化bean的时候已经看过了这里,快速过一下。
@Component
@Data
public class ZhangSan {
@Value("${name}")
private String name;
}
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取收集到的@Value,@Autowired注解的信息
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//看这里
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
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 {
//获取到@Value,@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) {
//反射设置到field中
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
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;
}
Class<?> type = descriptor.getDependencyType();
//获取到注解@Value里面的值 ${name}
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
//“${name}”是String类型
if (value instanceof String) {
//这里来解析${name}
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());
}
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()));
}
}
//省略部分源码
}
public String resolveEmbeddedValue(@Nullable String value) {
if (value == null) {
return null;
}
String result = value;
//PropertySourcesPlaceholderConfigurer类已经把占位符解析器添加进来了
//从embeddedValueResolvers获取占位符解析器
for (StringValueResolver resolver : this.embeddedValueResolvers) {
//调用占位符解析方法解析
result = resolver.resolveStringValue(result);
if (result == null) {
return null;
}
}
return result;
}