spring之PropertyOverrideConfigurer源码解析

本文深入解析Spring框架中PropertyOverrideConfigurer的源码,详细介绍其类结构、实现BeanFactoryPostProcessor接口的过程,以及如何通过配置文件直接修改Bean属性值。

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

PropertyOverrideConfigurer的介绍

上一篇博客spring之PropertyPlaceholderConfigurer源码解析中,介绍了BeanFactoryPostProcessor的一个应用例子PropertyPlaceholderConfigurer,这篇博客将介绍BeanFactoryPostProcessor的另外一个应用例子PropertyOverrideConfigurer。PropertyOverrideConfigurer的使用场景是,允许我们直接在properties文件中通过配置"bean.属性名称=属性值"的方式直接替换bean的属性值。

PropertyOverrideConfigurer的类结构

在这里插入图片描述
与上一篇博客分析的PropertyPlaceholderConfigurer的类结构类似,一样是继承了PropertyResourceConfigurer。

源码解析

PropertyResourceConfigurer实现BeanFactoryPostProcessor接口源码

由于与PropertyPlaceholderConfigurer一样是继承PropertyResourceConfigurer,这里我们再贴一下PropertyResourceConfigurer源码

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			Properties mergedProps = mergeProperties();
			//获取所有properties并合并转换
			// Convert the merged properties, if necessary.
			convertProperties(mergedProps);

			// Let the subclass process the properties.
			//主要过程还是调用子类的processProperties
			processProperties(beanFactory, mergedProps);
		}
		catch (IOException ex) {
			throw new BeanInitializationException("Could not load properties", ex);
		}
	}

PropertyOverrideConfigurer的processProperties方法源码

	@Override
	protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
			throws BeansException {
		//遍历所有的配置文件的属性名
		for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();) {
			String key = (String) names.nextElement();
			try {
				//执行processKey方法
				processKey(beanFactory, key, props.getProperty(key));
			}
			catch (BeansException ex) {
				String msg = "Could not process key '" + key + "' in PropertyOverrideConfigurer";
				if (!this.ignoreInvalidKeys) {
					throw new BeanInitializationException(msg, ex);
				}
				if (logger.isDebugEnabled()) {
					logger.debug(msg, ex);
				}
			}
		}
	}
	//分析processKey方法
	protected void processKey(ConfigurableListableBeanFactory factory, String key, String value)
			throws BeansException {
		//获取properties中属性名中字符“.”第一次出现的位置
		int separatorIndex = key.indexOf(this.beanNameSeparator);
		if (separatorIndex == -1) {
			//若properties中属性名不存在“.”,则不符合配置规则,抛出异常
			throw new BeanInitializationException("Invalid key '" + key +
					"': expected 'beanName" + this.beanNameSeparator + "property'");
		}
		//获取第一次字符“.”前面的串作为beanName
		String beanName = key.substring(0, separatorIndex);
		//后面的串作为beanProperty,作为applyPropertyValue方法的入参
		String beanProperty = key.substring(separatorIndex + 1);
		this.beanNames.add(beanName);
		//调用applyPropertyValue方法
		applyPropertyValue(factory, beanName, beanProperty, value);
		if (logger.isDebugEnabled()) {
			logger.debug("Property '" + key + "' set to value [" + value + "]");
		}
	}
	//分析applyPropertyValue方法
	protected void applyPropertyValue(
			ConfigurableListableBeanFactory factory, String beanName, String property, String value) {
		//先根据前面解析出来的beanName获取BeanDefinition
		BeanDefinition bd = factory.getBeanDefinition(beanName);
		//将bd复制给bdToUse
		BeanDefinition bdToUse = bd;
		while (bd != null) {
			bdToUse = bd;
			bd = bd.getOriginatingBeanDefinition();
		}
		//构造一对pv PropertyValue
		PropertyValue pv = new PropertyValue(property, value);
		pv.setOptional(this.ignoreInvalidKeys);
		//并调用MutablePropertyValues的addPropertyValue方法
		bdToUse.getPropertyValues().addPropertyValue(pv);
	}

MutablePropertyValues.addPropertyValue源码

	public MutablePropertyValues addPropertyValue(PropertyValue pv) {
		for (int i = 0; i < this.propertyValueList.size(); i++) {
			//遍历已有的pv,拿到相同的属性名之后,检查并替换值
			PropertyValue currentPv = this.propertyValueList.get(i);
			if (currentPv.getName().equals(pv.getName())) {
				pv = mergeIfRequired(pv, currentPv);
				setPropertyValueAt(pv, i);
				return this;
			}
		}
		this.propertyValueList.add(pv);
		return this;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值