写点什么

Spring 中 PropertyPlaceholderConfigurer 替换占位符的问题

  • 2023-03-26
    江西
  • 本文字数:1840 字

    阅读完需:约 6 分钟

最近在做项目的时候,碰到了一个问题,纠结了好久,现在记录一下

1 问题

多个 Maven 项目聚合的时候,每个 maven 都有自己的配置文件,并且都用了 PropertyPlaceholderConfigurer 替换占位符,然后启动的时候一直报错,说替换失败;问题症结就是 spirng配置多个PropertyPlaceholderConfigurer的问题

2 原因

在 spring bean 装配时,一个 PropertyPlaceholderConfigurer 就是一个后置处理器 BeanFactoryPostProcessor。在装配完 PropertyPlaceholderConfigurer 之后,就会触发 org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor>, ConfigurableListableBeanFactory)方法,代码如下:

/** * Invoke the given BeanFactoryPostProcessor beans. */private void invokeBeanFactoryPostProcessors(        Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    for (BeanFactoryPostProcessor postProcessor : postProcessors) {        postProcessor.postProcessBeanFactory(beanFactory);    }}
复制代码

假设一下,你配置了两个 PropertyPlaceholderConfigurer 实例 A 模板的 jdbc.xml 配置文件

<bean id="propertyConfigurer" class="com.zheng.common.plugin.EncryptPropertyPlaceholderConfigurer">        <property name="locations">            <list>                <value>classpath:jdbc.properties</value>                <value>classpath:redis.properties</value>            </list>        </property>    </bean>
复制代码

B 模板的 shiro.xml 配置文件

    <context:property-placeholder location="classpath*:zheng-upms-client.properties"/>
复制代码

然后 A 模板中的 jdbc.properties 和 B 中的 zheng-upms-client.properties 文件都在 A 模板中;A 依赖了 B;启动 A 项目,IOC 会先实例化这两个配置的 PropertyPlaceholderConfigurer;假如先实例化了 A 中的 PropertyPlaceholderConfigurer 实例,那么它会去替换所有被标记为 ${} 的占位符,这个时候替换到 B 模板中的一些占位符之后,肯定就会报错了,因为 B 模板中的占位符是在 zheng-upms-client.properties 这个属性文件中;

3 解决方案

4 一、使用一个 PropertyPlaceholderConfigurer 实例加载

 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="locations">            <list>                <value>classpath:jdbc.properties</value>                <value>classpath:redis.properties</value>                 <value>classpath:zheng-upms-client.properties</value>            </list>        </property>    </bean>
复制代码

但是这样解决真的是超级没有诚意了,本来就是解决不通模块之间的问题啊

5 二、配置加载顺序,并设置替换失败不报错

1.让 B 中的实例配置 order=1 先加载,并且设置 ignore-unresolvable="true"表示替换失败不报错

    <context:property-placeholder order="1" ignore-unresolvable="true" location="classpath*:zheng-upms-client.properties"/>

复制代码

2.设置 A 中,order=2 表示后加载,但是不设置 ignore-unresolvable 属性,因为最后还是要检查是否有剩余未替换的属性

        <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="order" value="2" />        <property name="locations">            <list>                <value>classpath:jdbc.properties</value>                <value>classpath:redis.properties</value>            </list>        </property>    </bean>
复制代码

6 总结

思路就是 当有多个实例的时候,让他们一个一个的去替换,替换失败不提示错误,等做后一个实例替换的时候如果还有没有被替换的就提示错误!所以要设置 order 来排序,因为必须让最后一个加载的去检查替换错误,之前的都可以不用检查

发布于: 2023-03-26阅读数: 16
用户头像

关注公众号: 石臻臻的杂货铺 获取最新文章 2019-09-06 加入

进高质量滴滴技术交流群,只交流技术不闲聊 加 szzdzhp001 进群 20w字《Kafka运维与实战宝典》PDF下载请关注公众号:石臻臻的杂货铺

评论

发布
暂无评论
Spring中PropertyPlaceholderConfigurer替换占位符的问题_spring-boot_石臻臻的杂货铺_InfoQ写作社区