spring PropertyOverrideConfigurer分析,带实例,带源码分析

"本文详细介绍了Spring中的PropertyOverrideConfigurer,作为BeanFactoryPostProcessor的子类,它允许在BeanDefinition创建Bean之前动态替换Bean的属性值。通过配置文件中的{beanName}
摘要由CSDN通过智能技术生成

1:写在前面

这篇文章中我们分析了BeanFactoryPostProcessor,知道了,其也是spring提供给我们的一个扩展点,这个是在外部配置生成BeanDefinition对象之后,在通过BeanDefinition创建spring bean之前,允许我们对BeanDefinition进行自己的定制化处理,本文要分析PropertyOverrideConfigurer就是BeanFacotryPostProcessor的一个子类,利用其实现了动态替换bean的属性值的功能,工程上用的不多,但是也有必要了解下。其和PropertyPlaceholderConfiguer(重要!!!)功能类似,感兴趣的也可以看下。

2:功能说明

该类允许我们按照{beanName}.{propName}={要替换的val}的格式在配置文件中定义信息,表达的含义就是替换bean名称为{beanName}的bean的属性{propName}的值为{要替换的val}

3:例子

3.1:测试的bean

public class MyPropertyOverrideConfigurerBean {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

3.2:xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"
          id="propertyOverrideConfigurer">
        <property name="locations">
            <list>
                <value>classpath:propertyoverrideconfigurertest/propertyoverrideconfigurertest.properties</value>
            </list>
        </property>
        <property name="fileEncoding" value="GBK"/>
    </bean>

    <bean class="yudaosourcecode.studyhelp.MyPropertyOverrideConfigurerBean"
          id="myPropertyOverrideConfigurerBean">
        <property name="name" value="张三"/>
    </bean>
</beans>

3.3:配置文件

myPropertyOverrideConfigurerBean.name=李四

3.4:测试

@Test
public void propertyoverrideconfigurertest() {
    ClassPathXmlApplicationContext ac
            = new ClassPathXmlApplicationContext("classpath:propertyoverrideconfigurertest/propertyoverrideconfigurertest.xml");
    System.out.println(ac.getBean("myPropertyOverrideConfigurerBean"));
}

运行:

{"age":0,"name":"李四"}

Process finished with exit code 0

可以看到name属性已经替换成李四了。

4:源码分析

该类与PropertyPlaceholderConfiguer一样,同样继承自PropertyResourceConfigurer,PropertyResourceConfigurer实现了postProcessBeanFactory方法,完成了获取配置文件信息等工作,然后调用processProperties方法执行具体的替换逻辑,我们就从这个方法开始分析。

4.1:processProperties

org.springframework.beans.factory.config.PropertyOverrideConfigurer#processProperties
protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
			throws BeansException {
	// 循环属性的名称,如myPropertyOverrideConfigurerBean.name=李四
	// myPropertyOverrideConfigurerBean.age=30这里获取的就是[myPropertyOverrideConfigurerBean.name,myPropertyOverrideConfigurerBean.age]
	for (Enumeration<?> names = props.propertyNames(); names.hasMoreElements();) {
		// 配置文件的key,如myPropertyOverrideConfigurerBean.name
		String key = (String) names.nextElement();
		try {
			// <2021-04-09 15:26>
			// 替换属性,props.getProperty(key)是获取要替换的新值
			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);
			}
		}
	}
}

<2021-04-09 15:26>处就是执行具体的属性替换的方法,详细参考4.2:processKey

4.2:processKey

源码如下:

org.springframework.beans.factory.config.PropertyOverrideConfigurer#processKey
protected void processKey(ConfigurableListableBeanFactory factory, String key, String value)
			throws BeansException {
	// 获取分隔符.的位置
	int separatorIndex = key.indexOf(this.beanNameSeparator);
	// 如果是没有分隔符.则抛出异常,处理配置错误的情况
	if (separatorIndex == -1) {
		throw new BeanInitializationException("Invalid key '" + key +
				"': expected 'beanName" + this.beanNameSeparator + "property'");
	}
	// 获取bean名称
	String beanName = key.substring(0, separatorIndex);
	// 获取要替换的属性名称
	String beanProperty = key.substring(separatorIndex + 1);
	this.beanNames.add(beanName);
	// <2021-04-09 16:49>,执行替换
	applyPropertyValue(factory, beanName, beanProperty, value);
	if (logger.isDebugEnabled()) {
		logger.debug("Property '" + key + "' set to value [" + value + "]");
	}
}

<2021-04-09 16:49>处源码如下:

org.springframework.beans.factory.config.PropertyOverrideConfigurer#applyPropertyValue
protected void applyPropertyValue(
			ConfigurableListableBeanFactory factory, String beanName, String property, String value) {

	BeanDefinition bd = factory.getBeanDefinition(beanName);
	BeanDefinition bdToUse = bd;
	while (bd != null) {
		bdToUse = bd;
		bd = bd.getOriginatingBeanDefinition();
	}
	// 使用新的替换值定义PropertyValue
	PropertyValue pv = new PropertyValue(property, value);
	pv.setOptional(this.ignoreInvalidKeys);
	// 添加新的替换老的
	bdToUse.getPropertyValues().addPropertyValue(pv);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值