PropertyPlaceholderConfigurer源码解析

本文引自我的个人博客: sunmingshuai.coding.me

这篇文章我们介绍一个常用的BFPP来消除我们心中的对BFPP的陌生感
spring配置文件中 读者一定经常遇到过${xxx}的写法 然后spring会帮我们替换成properties中对应的value值 那么这个变量是什么时候又是被哪个类替换的呢
在文章ClassPathXmlApplicationContext源码解析三:BFPP中我们提到了BFPP的概念 BFPP的全称是BeanFactoryPostProcessor是工厂级别的处理器 它的调用时间点是在将配置文件转化为BeanDefinition之后 加载成bean之前调用的
我们先看下配置文件

<bean id="dev_propertyPlace" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="2"/>
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath:config-sunms-dev.properties</value>
            </list>
        </property>
    </bean>

在使用这个bfpp之前当然是先获取这个bean 处理一些事情 比如将locations对应的string转化成需要的resource类型
既然是bfpp 那么我们的阅读入口就好找了 PropertyResourceConfigurer##postProcessBeanFactory()方法

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            //加载properties文件
            Properties mergedProps = mergeProperties();
            convertProperties(mergedProps);

            //替换
            processProperties(beanFactory, mergedProps);
        }
        catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }

spring的代码一直这么优雅 高度抽象 让人一看就知道要做什么事情
第一步就是加载我们指定的properties文件 第二步默认没有做什么事情
最后一步就是重点了

    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
            throws BeansException {

        StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
        doProcessProperties(beanFactoryToProcess, valueResolver);
    }

先是构建一个处理类 处理类不过是提供一些方法 定义了诸如前缀${ 后缀} 使后面的代码更简洁 然后交给doProcessProperties处理

protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
            StringValueResolver valueResolver) {

        BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);

        String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
        for (String curName : beanNames) {
            // Check that we're not parsing our own bean definition,
            // to avoid failing on unresolvable placeholders in properties file locations.
            if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
                BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
                try {
                    visitor.visitBeanDefinition(bd);
                }
                catch (Exception ex) {
                    throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
                }
            }
        }

        // New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
        beanFactoryToProcess.resolveAliases(valueResolver);

        // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
        // 处理如@Value("${name}")
        beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
    }

下面的代码就比较简单了 就是处理所有的BeanDefinitioin 不包含本身 将诸如parentName等属性中的${xxx}变量替换掉

    public void visitBeanDefinition(BeanDefinition beanDefinition) {
        visitParentName(beanDefinition);
        visitBeanClassName(beanDefinition);
        visitFactoryBeanName(beanDefinition);
        visitFactoryMethodName(beanDefinition);
        visitScope(beanDefinition);
        visitPropertyValues(beanDefinition.getPropertyValues());
        ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
        visitIndexedArgumentValues(cas.getIndexedArgumentValues());
        visitGenericArgumentValues(cas.getGenericArgumentValues());
    }

有趣的是最后一行代码

beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);

这句代码把构建好的工具类加入到了beanFactory中 是spring3.0加入的 加入的作用就是处理诸如@Value注解的时候 如果有${xxx}的形式的话 会被这个工具类给替换掉 这个在@Autowired注解工作原理源码解析的时候 我们会再提到

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值