spring之PropertyPlaceholderConfigurer源码解析

18 篇文章 0 订阅
17 篇文章 0 订阅

PropertyPlaceholderConfigurer介绍

上一篇博客spring之BeanFactoryPostProcessor源码解析中,通过源码分析了BeanFactoryPostProcessor的作用,这篇将介绍BeanFactoryPostProcessor的一个应用例子PropertyPlaceholderConfigurer。这里先直接介绍它的作用,然后再通过源码解析介绍。相信大部分人都使用过在spring的xml配置文件配置数据源,通常在配置数据源的ip和password等配置时,我们填写的是占位符,而真正的配置会配置在properties文件中。而PropertyPlaceholderConfigurer的作用就包含了上面说的这种场景,修改beanDefiniton真正的属性值为占位符对应的properties文件中配置的值。

PropertyPlaceholderConfigurer类结构

既然是BeanFactoryPostProcessor的一个例子,那说明PropertyPlaceholderConfigurer是有实现BeanFactoryPostProcessor接口。这里我们先分析一下其类结构
在这里插入图片描述
可以看到继承关系PropertyPlaceholderConfigurer->PlaceholderConfigurerSupport->PropertyResourceConfigurer。并且PropertyResourceConfigurer实现了BeanFactoryPostProcessor接口。

源码解析

PropertyResourceConfigurer实现的BeanFactoryPostProcessor接口源码

PropertyResourceConfigurer.java

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			//获取所有属性
			Properties mergedProps = mergeProperties();

			// Convert the merged properties, if necessary.
			//转换合并属性
			convertProperties(mergedProps);

			// Let the subclass process the properties.
			//子类实现属性替换过程
			processProperties(beanFactory, mergedProps);
		}
		catch (IOException ex) {
			throw new BeanInitializationException("Could not load properties", ex);
		}
	}

PropertyPlaceholderConfigurer实现父类的processProperties方法源码

	@Override
	protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
			throws BeansException {
		//将properties属性包装到String解析器PlaceholderResolvingStringValueResolver
		//此构造方法在下面的内部类中实现
		StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
		//执行父类PlaceholderConfigurerSupport的doProcessProperties方法
		doProcessProperties(beanFactoryToProcess, valueResolver);
	}
	
	//内部类
	private class PlaceholderResolvingStringValueResolver implements StringValueResolver {

		private final PropertyPlaceholderHelper helper;

		private final PlaceholderResolver resolver;

		public PlaceholderResolvingStringValueResolver(Properties props) {
			this.helper = new PropertyPlaceholderHelper(
					placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
			this.resolver = new PropertyPlaceholderConfigurerResolver(props);
		}

		@Override
		@Nullable
		public String resolveStringValue(String strVal) throws BeansException {
			String resolved = this.helper.replacePlaceholders(strVal, this.resolver);
			if (trimValues) {
				resolved = resolved.trim();
			}
			return (resolved.equals(nullValue) ? null : resolved);
		}
	}

PlaceholderConfigurerSupport.doProcessProperties源码

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}


	protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
			StringValueResolver valueResolver) {
		//构造BeanDefinitionVistor,即BeanDefinition访问器
		BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
		//获取容器中所有的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 {
					//遍历所有的BeanDefinition,并通过前面构造的访问器,将BeanDefinition作为参数执行visitBeanDefinition方法
					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.
		beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
	}

BeanDefinitionVisitor.visitBeanDefinition源码

	public void visitBeanDefinition(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());
		}
	}
	
	//分析visitPropertyValues
	protected void visitPropertyValues(MutablePropertyValues pvs) {
		PropertyValue[] pvArray = pvs.getPropertyValues();
		for (PropertyValue pv : pvArray) {
			//这里通过遍历beanDefiniton原有属性值,尝试通过解析器获得一个新的值,如果你到新值则替换掉旧的值
			Object newVal = resolveValue(pv.getValue());
			if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
				pvs.add(pv.getName(), newVal);
			}
		}
	}
	
	//分析resolveValue
	@Nullable
	protected Object resolveValue(@Nullable Object value) {
		//按照预想分析,value是一个String类型,因此省略掉一大段类型判断的源码。
		else if (value instanceof String) {
			//最终调用resolveStringValue
			return resolveStringValue((String) value);
		}
		return value;
	}
	
	//分析resolveStringValue
	@Nullable
	protected String resolveStringValue(String strVal) {
		if (this.valueResolver == null) {
			throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
					"object into the constructor or override the 'resolveStringValue' method");
		}
		//这里最终调用了解析器的resolveStringValue方法
		String resolvedValue = this.valueResolver.resolveStringValue(strVal);
		// Return original String if not modified.
		return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
	}

PlaceholderResolvingStringValueResolver.resolveStringValue源码

前面分析了PropertyPlaceholderConfigurer的内部类PlaceholderResolvingStringValueResolver,这个类就定义resolveStringValue方法,继续前面的调用链下来到了resolveStringValue方法

private class PlaceholderResolvingStringValueResolver implements StringValueResolver {

		private final PropertyPlaceholderHelper helper;

		private final PlaceholderResolver resolver;

		public PlaceholderResolvingStringValueResolver(Properties props) {
			this.helper = new PropertyPlaceholderHelper(
					placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
			this.resolver = new PropertyPlaceholderConfigurerResolver(props);
		}

		@Override
		@Nullable
		public String resolveStringValue(String strVal) throws BeansException {
			//最终是通过PropertyPlaceholderHelper帮助类进行辅助解析占位符
			String resolved = this.helper.replacePlaceholders(strVal, this.resolver);
			if (trimValues) {
				resolved = resolved.trim();
			}
			return (resolved.equals(nullValue) ? null : resolved);
		}
	}

PropertyPlaceholderHelper.replacePlaceholders源码

	public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
		Assert.notNull(value, "'value' must not be null");
		//调用parseStringValue
		return parseStringValue(value, placeholderResolver, new HashSet<>());
	}
	//真正的占位符解析过程,其实就是解析${}这样的一个过程。有兴趣的可以自行研读
	protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {

		StringBuilder result = new StringBuilder(value);

		int startIndex = value.indexOf(this.placeholderPrefix);
		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.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...
				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;
						}
					}
				}
				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();
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值