zoukankan      html  css  js  c++  java
  • spring 之 property-placeholder 分析

    不难知道, property-placeholder 的解析是 PropertyPlaceholderBeanDefinitionParser 完成的, 但是 它仅仅是个parser , 它仅仅是读取了 location 等配置属性, 并没有完成真正的解析,及 注册。

    <context:property-placeholder location="appa.properties"/>

    我们把 location 设置为一个错误的 路径,就会报错, 从错误堆栈中可以看出, 实际的解析是 PropertySourcesPlaceholderConfigurer 完成的: 

    警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not exist
    Exception in thread "main" org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not exist
    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:148)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:161)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at LKtest.main(LKtest.java:11)
    Caused by: java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
    at org.springframework.core.io.support.EncodedResource.getInputStream(EncodedResource.java:154)
    at org.springframework.core.io.support.PropertiesLoaderUtils.fillProperties(PropertiesLoaderUtils.java:98)
    at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:177)
    at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:158)
    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:139)
    ... 7 more

    但是, PropertyPlaceholderBeanDefinitionParser具体是 何时被注册的呢? 我纠结了很久, 仔细调试代码,终于发现了奥秘:


    at org.springframework.context.config.PropertyPlaceholderBeanDefinitionParser.getBeanClass(PropertyPlaceholderBeanDefinitionParser.java:48)
    at org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser.parseInternal(AbstractSingleBeanDefinitionParser.java:66)  // 又交给了实际的子类去parse 
    at org.springframework.beans.factory.xml.AbstractBeanDefinitionParser.parse(AbstractBeanDefinitionParser.java:61)
    at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1411)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1401)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:172)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:142)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:613)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:514)
    - locked <0x5d2> (a java.lang.Object)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at LKtest.main(LKtest.java:11)

    原来是在解析 property-placeholder 这个xml元素的时候完成的, parseCustomElement 。

    解析 property-placeholder的时候,找到了 PropertyPlaceholderBeanDefinitionParser 。 然后把 配置中的location 交给了它处理。 

        AbstractSingleBeanDefinitionParser:
        protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
            String parentName = this.getParentName(element);
            if(parentName != null) {
                builder.getRawBeanDefinition().setParentName(parentName);
            }
    
            Class<?> beanClass = this.getBeanClass(element);  根据context:property-placeholder, 找到class。返回的正是 PropertySourcesPlaceholderConfigurer 
            
            ..
            
        }
        
        
        PropertyPlaceholderBeanDefinitionParser:
        protected Class<?> getBeanClass(Element element) {
            return "ENVIRONMENT".equals(element.getAttribute("system-properties-mode"))?PropertySourcesPlaceholderConfigurer.class:PropertyPlaceholderConfigurer.class;
        }
            

    但是我还是不知道 properties 文件是如何被读取和解析的, 直到我注意到 PropertySourcesPlaceholderConfigurer 实现了 BeanFactoryPostProcessor :

    at org.springframework.core.io.support.PropertiesLoaderUtils.fillProperties(PropertiesLoaderUtils.java:85)
    at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:177)  // 这里完成了properties 的读取
    at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:158)
    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:139) // 因为PropertySourcesPlaceholderConfigurer 实现了 BeanFactoryPostProcessor
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:161)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)
    - locked <0x6c6> (a java.lang.Object)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at LKtest.main(LKtest.java:11)

    具体来说:

        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            if(this.propertySources == null) {
                this.propertySources = new MutablePropertySources();
                if(this.environment != null) {
                    this.propertySources.addLast(new PropertySource<Environment>("environmentProperties", this.environment) {
                        public String getProperty(String key) {
                            return ((Environment)this.source).getProperty(key);
                        }
                    });
                }
    
                try {
                    PropertySource<?> localPropertySource = new PropertiesPropertySource("localProperties", this.mergeProperties());  // BeanFactory 创建完成后, 读取所有的 properties 文件
                    if(this.localOverride) {
                        this.propertySources.addFirst(localPropertySource);
                    } else {
                        this.propertySources.addLast(localPropertySource);
                    }
                } catch (IOException var3) {
                    throw new BeanInitializationException("Could not load properties", var3);
                }
            }
    
            this.processProperties(beanFactory, (ConfigurablePropertyResolver)(new PropertySourcesPropertyResolver(this.propertySources)));// 将properties 文件内容应用到所有的配置中去,也就是替换 ${} 部分
            this.appliedPropertySources = this.propertySources;
        }
        
        
        
        对 ${} 的替换:
    at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitPropertyValues(BeanDefinitionVisitor.java:142)
          at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitBeanDefinition(BeanDefinitionVisitor.java:82)
          at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:220) // 完成了所有的beanDefinition 的预处理之后, 开始替换 Placeholder
          at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.processProperties(PropertySourcesPlaceholderConfigurer.java:180)
          at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:152)
          ...
          
    
        protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) {
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
            String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();   // 获取所有已经注册的 bean 定义
            String[] var5 = beanNames;
            int var6 = beanNames.length;
    
            for(int var7 = 0; var7 < var6; ++var7) {
                String curName = var5[var7];
                if(!curName.equals(this.beanName) || !beanFactoryToProcess.equals(this.beanFactory)) {
                    BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
    
                    try {
                        visitor.visitBeanDefinition(bd);
                    } catch (Exception var11) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, var11.getMessage(), var11);
                    }
                }
            }
    
            beanFactoryToProcess.resolveAliases(valueResolver);
            beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
        }
        
        
        
        PropertySourcesPlaceholderConfigurer的父类定义了 如何设置 placeholder, 可见前缀和后缀:
        public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer implements BeanNameAware, BeanFactoryAware {
            public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
            public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
            public static final String DEFAULT_VALUE_SEPARATOR = ":";
            protected String placeholderPrefix = "${";
            protected String placeholderSuffix = "}";
            protected String valueSeparator = ":";
            
            
            
            PropertySource 就是一个kv 配置项。
            
          
          其中位于 BeanDefinitionVisitor :
        public void visitBeanDefinition(BeanDefinition beanDefinition) {
            this.visitParentName(beanDefinition);
            this.visitBeanClassName(beanDefinition);
            this.visitFactoryBeanName(beanDefinition);
            this.visitFactoryMethodName(beanDefinition);
            this.visitScope(beanDefinition);
            this.visitPropertyValues(beanDefinition.getPropertyValues());
            ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
            this.visitIndexedArgumentValues(cas.getIndexedArgumentValues());
            this.visitGenericArgumentValues(cas.getGenericArgumentValues());
        }
          
  • 相关阅读:
    mongodb.conf配置文件
    mongodb创建普通角色和普通用户
    add unique index 注意事项
    error: src refspec master does not match any
    innodb_data_file_path配置变更引发mysql重启失败
    time_zone参数配置
    主键有无检测
    gdb在线修改mysql变量
    mybatis连接数据库
    mongo登录
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/7826580.html
Copyright © 2011-2022 走看看