本文重点是通过例子代码的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阶段完成属性设置