PropertyPlaceholderConfigurer

PropertyPlaceholderConfigurer的类图如下,可以看到其也是一个BeanFactoryPostProcessor

例子代码报错

public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("application.xml");
        UserBean userBean = (UserBean) applicationContext.getBean("userBean");
        System.out.println(userBean.getName());
    }
<?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="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

注意到app1.properties是注释掉的,执行后报错如下

追踪源码看报错

当执行org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()时可以看到有2个bfpp,一个是placeholderConfigurer1,一个是placeholderConfigurer2,这里先执行的是placeholderConfigurer1

bfpp的顺序问题?

回到:org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()的如下代码

// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
    if (processedBeans.contains(ppName)) {
        // skip - already processed in first phase above
    }
    else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }
    else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
        orderedPostProcessorNames.add(ppName);
    }
    else {
        nonOrderedPostProcessorNames.add(ppName);
    }
}

且注意到PropertyPlaceholderConfigurer是实现了PriorityOrdered的,我们也配置了顺序

执行到第一个placeholderConfigurer1找不到配置即报错?为什么不接着找placeholderConfigurer2

执行org.springframework.beans.factory.config.PropertyResourceConfigurer#postProcessBeanFactory

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    try {
        Properties mergedProps = mergeProperties();

        // Convert the merged properties, if necessary.
        convertProperties(mergedProps);

        // Let the subclass process the properties.
        processProperties(beanFactory, mergedProps);
    }
    catch (IOException ex) {
        throw new BeanInitializationException("Could not load properties", ex);
    }
}

mergedProp获取为空,在processProperties(beanFactory, mergedProps);这句报错了,进入到方法内部报错如下

placeholderConfigurer1的BeanDefinitionVisitor在解析${app.name}报错找不到

继续debug下去可以看到最后的报错位置如下,注意到ignoreUnresolvablePlaceholders=false,即【不忽略解析错误】是false, 可以看到如果是true就不会抛出异常了

根据debug分析尝试修改ignoreUnresolvablePlaceholders=true

<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>

重新运行且成功拿到了配置2的值

多个配置覆盖问题

经过上一个报错,就会有个疑问,如果配置有多个且争取,那么到底最后会是哪一个?

实际执行是order更小的,即第一个bfpp能正常解析到的配置就是userBean的配置值

跟踪源码解释

placeholderConfigurer1正确执行后userBean的BeanDefinition已经正确赋值了${app.name}的值

当placeholderConfigurer2正确执行时:如下(可以理解为之前都解析好了,这次还解析个鬼)

附第一次解析对比:(如下,才是真正的解析)

Copyright @doctording all right reserved,powered by Gitbook该文件修改时间: 2022-05-17 23:51:55

results matching ""

    No results matching ""