Spring 工具类 : PlaceholderConfigurerSupport

本文介绍了一个用于解析定义中属性值占位符的抽象工具类。它继承自特定类,具备指定属性源、合并属性等能力,实现了相关接口。围绕占位符属性替换逻辑,提供格式设置和规则开关功能,核心方法可进行占位符解析替换,还提及类似工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

介绍

PlaceholderConfigurerSupportSpring提供的一个工具类,用于解析bean定义中属性值里面的占位符,这是一个抽象类,不能被直接实例化使用。

PlaceholderConfigurerSupport继承自PropertyResourceConfigurer,而PropertyResourceConfigurer具备如下能力 :

  1. 指定属性源;
    • Properties对象形式指定的本地属性源,
    • 需要从文件路径中加载的外部属性源
  2. 合并属性源中的属性;
  3. bean工厂(可以直接理解为IoC容器)做某种处理
  4. 实现了接口BeanFactoryPostProcessor,可以在容器后置处理阶段做些事情

PlaceholderConfigurerSupportPropertyResourceConfigurer的基础上对上面第三点提到的"某种处理"做出了明确实现,也就是替换所有bean定义中属性值和构造函数参数值中的特定格式的属性占位符。

围绕自己的占位符属性替换逻辑,PlaceholderConfigurerSupport提供了相应的占位符格式设置功能,解析过程中的一些规则的开关功能。具体如下:

  1. 占位符格式设置功能 :

    • 设置占位符前缀,缺省为 ${
    • 设置占位符后缀,缺省为 }
    • 设置占位符缺省值分隔符,缺省为 :

    缺省情况下,也就是会处理如下格式的占位符 :

    • @Value("${person.age}")
    • <property name="driverClassName" value="${driver}"/>
    • <property name="url" value="jdbc:${dbname:defaultdb}"/>
  2. 解析规则设置功能 :

    • 是否修剪值前后的空白,

      缺省为 : 不修剪值前后的空白

    • 遇到不可解析的占位符时是否抛出异常

      缺省为 : 遇到不可解析的占位符时抛出异常 BeanDefinitionStoreException

PlaceholderConfigurerSupport的方法#doProcessProperties是其核心逻辑,该方法对容器中除了自己(PlaceholderConfigurerSupport bean自己)之外的所有bean定义中的属性值,构造函数参数值进行了属性占位符到相应属性值的解析和替换。

PlaceholderConfigurerSupport自身并没有实现基类PropertyResourceConfigurer定义的抽象方法abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props),该方法的真正目的才是基于指定属性源对容器进行某种操作,该方法留给PlaceholderConfigurerSupport的实现子类使用,具体的可以参考SpringPlaceholderConfigurerSupport的内置实现子类PropertySourcesPlaceholderConfigurerPropertySourcesPlaceholderConfigurer正是实现了该方法,基于指定的属性源,在其中使用PlaceholderConfigurerSupport提供的方法#doProcessProperties进行了所定义的处理逻辑。

PlaceholderConfigurerSupport类似的另外一个属性值解析工具是PropertyOverrideConfigurerPlaceholderConfigurerSupport是分析每个bean定义内属性值中的占位符将它们替换成相应的属性值,而PropertyOverrideConfigurer则是解析和处理所有类似beanName.property=value这种格式的属性设置。

继承关系

PlaceholderConfigurerSupport

源代码

源代码版本 : Spring Beans 5.1.5.RELEASE


package org.springframework.beans.factory.config;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;


public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer
		implements BeanNameAware, BeanFactoryAware {

	/** Default placeholder prefix: ${ */
	public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";

	/** Default placeholder suffix: } */
	public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";

	/** Default value separator: : */
	public static final String DEFAULT_VALUE_SEPARATOR = ":";


	/** Defaults to #DEFAULT_PLACEHOLDER_PREFIX. */
	protected String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX;

	/** Defaults to #DEFAULT_PLACEHOLDER_SUFFIX. */
	protected String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX;

	/** Defaults to #DEFAULT_VALUE_SEPARATOR. */
	@Nullable
	protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;

	protected boolean trimValues = false;

	@Nullable
	protected String nullValue;

	protected boolean ignoreUnresolvablePlaceholders = false;

	@Nullable
	private String beanName;

	@Nullable
	private BeanFactory beanFactory;


	/**
	 * Set the prefix that a placeholder string starts with.
	 * The default is #DEFAULT_PLACEHOLDER_PREFIX.
	 */
	public void setPlaceholderPrefix(String placeholderPrefix) {
		this.placeholderPrefix = placeholderPrefix;
	}

	/**
	 * Set the suffix that a placeholder string ends with.
	 * The default is #DEFAULT_PLACEHOLDER_SUFFIX.
	 */
	public void setPlaceholderSuffix(String placeholderSuffix) {
		this.placeholderSuffix = placeholderSuffix;
	}

	/**
	 * Specify the separating character between the placeholder variable
	 * and the associated default value, or null if no such
	 * special character should be processed as a value separator.
	 * The default is #DEFAULT_VALUE_SEPARATOR.
	 */
	public void setValueSeparator(@Nullable String valueSeparator) {
		this.valueSeparator = valueSeparator;
	}

	/**
	 * Specify whether to trim resolved values before applying them,
	 * removing superfluous whitespace from the beginning and end.
	 * Default is false.
	 * @since 4.3
	 */
	public void setTrimValues(boolean trimValues) {
		this.trimValues = trimValues;
	}

	/**
	 * Set a value that should be treated as null when resolved
	 * as a placeholder value: e.g. "" (empty String) or "null".
	 * Note that this will only apply to full property values,
	 * not to parts of concatenated values.
	 * 
	 * By default, no such null value is defined. This means that
	 * there is no way to express null as a property value
	 * unless you explicitly map a corresponding value here.
	 */
	public void setNullValue(String nullValue) {
		this.nullValue = nullValue;
	}

	/**
	 * Set whether to ignore unresolvable placeholders.
	 * Default is "false": An exception will be thrown if a placeholder fails
	 * to resolve. Switch this flag to "true" in order to preserve the placeholder
	 * String as-is in such a case, leaving it up to other placeholder configurers
	 * to resolve it.
	 */
	public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) {
		this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
	}

	/**
	 * Only necessary to check that we're not parsing our own bean definition,
	 * to avoid failing on unresolvable placeholders in properties file locations.
	 * The latter case can happen with placeholders for system properties in
	 * resource locations.
	 * @see #setLocations
	 * @see org.springframework.core.io.ResourceEditor
	 */
	@Override
	public void setBeanName(String beanName) {
		this.beanName = beanName;
	}

	/**
	 * Only necessary to check that we're not parsing our own bean definition,
	 * to avoid failing on unresolvable placeholders in properties file locations.
	 * The latter case can happen with placeholders for system properties in
	 * resource locations.
	 * @see #setLocations
	 * @see org.springframework.core.io.ResourceEditor
	 */
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}


	// 该方法是 PlaceholderConfigurerSupport 对容器中所有 bean 定义进行处理的核心逻辑方法,
	// 该方法留给具体实现子类使用,当然具体实现子类也可以重写该方法或者不使用该方法。
	// 
	// Spring 提供的 PlaceholderConfigurerSupport 具体实现子类 PropertyPlaceholderConfigurer
	// 直接使用了该方法。
	protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
			StringValueResolver valueResolver) {

		//  BeanDefinitionVisitor 是一个专门为 PropertyPlaceholderConfigurer 设计的 bean 定义
		// 访问器,主要是遍历 bean 定义中的属性值和构造函数参数值字符串,使用 valueResolver
		// 解析相应值字符串中的占位符,结合给定的属性源,将占位符其替换为相应的属性值
		BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

		// 获取容器中所有的 bean 名称,这样可以访问到容器中所有的 bean 定义 
		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.
          // this.beanName 记录了当前对象,也就是当前 PlaceholderConfigurerSupport 对象的
          // bean 名称,这里的 for 循环会使用 visitor 处理处理当前 PlaceholderConfigurerSupport 对象
          // 之外的所有 bean 定义
			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.
       // bean 的别名,以及别名的目标bean名称中也可能使用占位符,这里也做处理 
		beanFactoryToProcess.resolveAliases(valueResolver);

		// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
       // 将这里所使用的值解析器 valueResolver 添加到容器,用于处理类似注解属性中的嵌入值。 
		beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
	}

}

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值