本文重点是通过例子代码的debug了解PropertyPlaceholderConfigurer的原理
更多可阅读:placeholderconfigurer文档 了解
目录
- 测试程序如下
- PropertyPlaceholderConfigurer
- placeholderConfigurer1 & placeholderConfigurer2的执行
- userbean的BeanDefinition应用PropertyPlaceholderConfigurer前:
- userbean的BeanDefinition应用PropertyPlaceholderConfigurer后:
- userBean的name的set
- 总结
测试程序如下
public class TestPropertyPlaceholderConfigurer {
public static void main(String[] args) throws Exception{
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("application.xml");
UserBean userBean = (UserBean) applicationContext.getBean("userBean");
System.out.println(userBean.getName());
}
}
application.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 https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="placeholderConfigurer1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="1"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:app1.properties</value>
</list>
</property>
</bean>
<bean id="placeholderConfigurer2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="2"/>
<property name="locations">
<list>
<value>classpath:app2.properties</value>
</list>
</property>
</bean>
<bean name="userBean" class="com.example.demoapi.test.UserBean">
<property name="name" value="${app.name}"/>
</bean>
</beans>
app1.properties:
app.name=v1
app2.properties:
app.name=v2
userBean
public class UserBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
改变优先级输出的不同:
PropertyPlaceholderConfigurer
类图如下:
可以看到是个BeanFactoryPostProcessor 且实现了顺序的;回顾ApplicationContext的refresh方法之invokeBeanFactoryPostProcessors,可以知晓执行这些BeanFactoryPostProcessor是有先后次序的。- - - 顺带复习:AnnotationConfigApplicationContext流程看@Configuration,@ComponentScan,@Import等的处理
placeholderConfigurer1 & placeholderConfigurer2的执行
上述placeholderConfigurer1,placeholderConfigurer2两个bean在invokeBeanFactoryPostProcessors的如下地方完成了实例化
这两个实例化出来的PropertyPlaceholderConfigurer接着排序
接着执行调用bfpp的postProcessBeanFactory方法
org.springframework.beans.factory.config.PropertyResourceConfigurer#postProcessBeanFactory
构造placeholderConfigurer2的PlaceholderResolvingStringValueResolver,然后进行beanDefinition合并操作
org.springframework.beans.factory.config.PlaceholderConfigurerSupport#doProcessProperties
userbean的BeanDefinition应用PropertyPlaceholderConfigurer前:
userbean的BeanDefinition应用PropertyPlaceholderConfigurer后:
因为PropertyPlaceholderConfigurer不同的order导致应用的先后不同,order更小的PropertyPlaceholderConfigurer先应用了;后面的应用就无效了
所以最后是PropertyPlaceholderConfigurer order更小的那个。
userBean的name的set
回顾bean的生命周期:https://doctording.blog.csdn.net/article/details/145044487
在userBean的属性设置populateBean阶段,获取到bean的所有PropertyValue,逐一设置
最后反射设置完成:
总结
- 普通bean应用PropertyPlaceholderConfigurer的时候,如果有多个PropertyPlaceholderConfigurer,应该要有顺序,属性相同的取order小的即高优先级的
- 具体是通过PropertyPlaceholderConfigurer改变BeanDefintion, 后续bean生命周期的populateBean阶段完成属性设置