文章目录
先回顾一下我们在 spring 中是如何使用占位符的
application.xml
<!-- 通过配置PropertyPlaceholderConfigurer的bean来扫描 properties 文件 -->
<bean id="placeHolder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" >
<value>classpath*:*.properties</value >
</property>
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、username、password -->
<property name="url" value="jdbc:mysql://${mysql.host}:${mysql.port}/${mysql.database}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.passwd}"/>
</bean>
app.properties
mysql.host=127.0.0.1
mysql.port=3306
mysql.database=db_user
mysql.username=root
mysql.passwd=123456
PropertyPlaceholderConfigurer类解析
根据类图大概可以看出来spring实现占位符替换主要涉及到BeanFactoryPostProcessor
接口和PropertyPlaceholderConfigurer
、PlaceholderConfigurerSupport
、PropertyResourceConfigurer
三个类
先来分析BeanFactoryPostProcessor接口
Spring提供了的一种叫做BeanFactoryPostProcessor
的容器扩展机制。它允许我们在容器实例化对象之前,对容器中的BeanDefinition中的信息做一定的修改(比如对某些字段的值进行修改,这就是占位符替换的根本)。
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
什么意思呢?就是只要向 Spring 容器注入了 BeanFactoryPostProcessor
接口的实现类,那么在容器实例化对象之前会先调用这个类的postProcessBeanFactory
方法,而PropertyPlaceholderConfigurer
类正是间接实现了BeanFactoryPostProcessor
接口才完成了占位符的实现(看上面的类图)
我们看到这个接口的参数是ConfigurableListableBeanFactory
类的一个对象,实际开发中,我们常使用它的getBeanDefinition()方法获取某个bean的元数据定义:BeanDefinition。它有这些方法:
真正实现来BeanFactoryPostProcessor接口的是PropertyResourceConfigurer类,来看看它如何实现postProcessBeanFactory方法的
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
// 把加载的所有的 properties 文件中的键值对都取出来
Properties mergedProps = mergePro