美文网首页Spring
Spring Properties Loader

Spring Properties Loader

作者: KengG | 来源:发表于2017-11-14 20:01 被阅读279次

            最近在做Spring项目时,使用到了@Value注解,可以动态注入到注解了@Value的属性上;一般我们会把用到的属性(key/value值)统一放到一个或者多个properties文件中,Spring启动时加载properties把属性读到Spring Property组件中,后续的注入交由组件完成。

            我们一贯的做法是在application.xml 中,加载PropertiesLoaderSupport组件;

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:content="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/p http://www.springframework.org/schema/p/spring-p.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="location" value="classpath*:config.properties" />
        </bean>
    </beans>
    

    结构


            由于PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口;BeanFactory在加载的时候会调用该接口;

    那我们看看加载过程;

    首先来看看类结构:

    PropertyPlaceholderConfigurer
    package org.springframework.beans.factory.config;
    
    import org.springframework.beans.BeansException;
    
    public interface BeanFactoryPostProcessor {
        void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }
    

    看看postProcessBeanFactory 在BeanFactory初始化时在哪里调用的,我会先从哪个地方调用了这个方法,一步一步找到,最初加载调用的地方;

    使用IDEA的同学可以按住ctrl 键,鼠标点击该方法

    除了第二行,其它显示的都是注释;鼠标点击第二行进入;最终会跳到:

    PostProcessorRegistrationDelegate

    这个是一个静态的私用方法,在找(由于代码太长我就不粘出来了;大家可以去找找看)

    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法调用了本类中的静态方法 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors

    那我们就找哪里调用了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法;

    AbstractApplicationContext

    发现跳到AbstractApplicationContext类中;而AbstractApplicationContext是所有实现ApplicationContext子类的抽象父类;

    我们在看看那个地方调用了AbstractApplicationContext.invokeBeanFactoryPostProcessors;

    AbstractApplicationContext.refresh

    最终找到了加载properties的源头,refresh()方法我就过多介绍了;

    如何加载Properties


    上面我们知道类的加载过程,接下来看看properties如何加载的。

    回到PlaceholderConfigurerSupport.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);
        }
    }
    
    • mergeProperties ()

      改方法主要做了两件事

      • 加载properties文件 loadProperties()
      • 合并指定的Property (参考原码)
    • convertProperties()

      该方法没有做什么处理,但是有兴趣的同学可以看看源码,去了解一下;

    • processProperties()

      这是个抽象方法,交由子类实现;

      子类就是文件开头介绍的PropertyPlaceholderConfigurer,看看该类实现了什么功能。

      @Override
      protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
              throws BeansException {
      
          StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
      
          this.doProcessProperties(beanFactoryToProcess, valueResolver);
      }
      

      Spring 最终把处理${} 或者 @Value的方式交由StringValueResolver来完成;

    源码介绍的不够全面,需要你进入源码中,一步一步去理解。

    如何解析Properties


    通过看源码发现最终属性解析是在PropertyPlaceholderConfigurer.resolvePlaceholder方法中。

    protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) {
            String propVal = null;
            if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) {
                propVal = resolveSystemProperty(placeholder);
            }
            if (propVal == null) {
                propVal = resolvePlaceholder(placeholder, props);
            }
            if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) {
                propVal = resolveSystemProperty(placeholder);
            }
            return propVal;
        }
    
    参数介绍
    • placeholder

      要解析的属性key

    • props

      PlaceholderConfigurerSupport.postProcessBeanFactory()方法中解析的properties

    • systemPropertiesMode

      有三个值

      • SYSTEM_PROPERTIES_MODE_NEVER

        不从System.getProperty()中获取placeholder对应的值。

      • SYSTEM_PROPERTIES_MODE_FALLBACK

        如果props中找不到placeholder对应的值,就从System.getProperty()或者System.getenv()中找。

      • SYSTEM_PROPERTIES_MODE_OVERRIDE

        优先从System.getProperty()或者System.getenv()中找placeholder对应的值,如果找不到,才会从props中找

        • System.getProperty()

          如果systemPropertiesMode的值为 SYSTEM_PROPERTIES_MODE_FALLBACKSYSTEM_PROPERTIES_MODE_OVERRIDE时,默认是从System.getProperty()中查找的;

        • System.getenv()

          如果System.getProperty()中没有有效的值,才会到System.getenv()中查找;但是要从System.getenv()中查找是受PropertyPlaceholderConfigurer.searchSystemEnvironment限制。

    写到最后我们总结一下PropertyPlaceholderConfigurer

    加载
    • properties 文件
    • localProperties

      这个要指定合并的Properties

    解析
    • props
    • System.getProperty()
    • System.getenv()

    Spring 版本 4+
    具体实现参考源码。

    • PropertyPlaceholderConfigurer
    • BeanFactoryPostProcessor
    • AbstractApplicationContext
    • PostProcessorRegistrationDelegate
    • PlaceholderResolvingStringValueResolver
    • PropertyPlaceholderConfigurerResolver
    • SpringProperties
    • spring.properties

    最后可以看看 PropertySourcesPlaceholderConfigurerPropertyPlaceholderConfigurer的实现方式有什么不一样?

    相关文章

      网友评论

        本文标题:Spring Properties Loader

        本文链接:https://www.haomeiwen.com/subject/ipafvxtx.html