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()); } 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode面试题 10.02. 变位词组

编写一种方法&#xff0c;对字符串数组进行排序&#xff0c;将所有变位词组合在一起。变位词是指字母相同&#xff0c;但排列不同的字符串。 注意&#xff1a;本题相对原题稍作修改 示例: 输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”], 输出: [ [“ate”,…

hacktoberfest_我第一次参加Hacktoberfest中学到了什么

hacktoberfestImposter syndrome is something we all struggle with to one degree or another. Imposter syndrome is the fear of exposure as a fraud. If you’re anything like me you have felt like your work was not good enough to show. Or you weren’t far along…

--save 和--save-dev的区别

npm install 在安装 npm 包时&#xff0c;有两种命令参数可以把它们的信息写入 package.json 文件&#xff0c;一个是npm install --save另一个是 npm install --save-dev&#xff0c;他们表面上的区别是--save 会把依赖包名称添加到 package.json 文件 dependencies 键下&…

Linux 文件区块连续吗,关于Linux文件系统的的简单理解和认识

关于Linux文件系统的的简单理解和认识关于文件系统的运作&#xff0c;这与操作系统带的档案数据有关。例如Linux操作系统的档案权限(rwx)与文件属性(拥有者&#xff0c;群组&#xff0c;时间参数等)。文件系统通常会将这两部分的数据分别存放在不同的区块&#xff0c;权限与属性…

服务器性能和活动监视

监视数据库的目的是评估服务器的性能。 有效监视包括定期拍摄当前性能的快照来隔离导致问题的进程&#xff0c;以及连续收集数据来跟踪性能趋势。 Microsoft SQL Server 和 Microsoft 操作系统提供实用工具&#xff0c;使您可以查看数据库的当前状态并跟踪性能的状态变化。 下一…

Microsoft Desktop Virtualization

基本上有两套啦&#xff0c;一是大家较为熟悉的MED-V。另外就是VDI(虚拟桌面基础架构)&#xff0c;也就是以下的组合&#xff1a;1、Windows Server 2008 with Hyper-V 2、System Center Virtual Machine Manager (VMM) 2008 VMM 20083、Windows Vista Enterprise Centralized …

leetcode60. 第k个排列(回溯算法)

给出集合 [1,2,3,…,n]&#xff0c;其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况&#xff0c;并一一标记&#xff0c;当 n 3 时, 所有排列如下&#xff1a; “123” “132” “213” “231” “312” “321” 给定 n 和 k&#xff0c;返回第 k 个排列。 说明&…

webpack设置应用缓存_如何使用Webpack在Rails应用程序中设置TinyMCE

webpack设置应用缓存by Joanna Gaudyn乔安娜高登(Joanna Gaudyn) 如何使用Webpack在Rails应用程序中设置TinyMCE (How to setup TinyMCE in your Rails app using Webpack) The popularity of using Webpack to deal with your assets in Rails is steadily increasing. Getti…

springmvc ajax 页面无法重定向问题!!!!

诶诶诶。这个问题困扰了我一天&#xff0c;百度了很多都不行。 刚实战ssm框架&#xff0c;做登录跳转的时候&#xff0c;我是用ajax提交数据到后台&#xff0c;然后后天返回数据进前台&#xff0c;前台再给用户一些比较友好的提示&#xff0c;比如用户名或密码错误之类的。 所以…

linux svn log 乱码,解决p42svn中文log乱码的问题

现象&#xff1a;将perforce代码库迁移至SVN时log乱码。p42svn.pl在windows下运行至"-|"时会报错&#xff0c;于是安装了linux虚拟机&#xff0c;从虚拟linux中运行p42svn.pl生成dump文件&#xff0c;再传至windows下用svnadmin load。可是在svn查看log时&#xff0…

Django开发中常用的命令总结

1. 创建一个Django Project#使用下面的命令可以创建一个projectdjango-admin.py startproject mysite #创建好之后可以看到如下的pro... 1. 创建一个Django Project 1 2 3 4 5 6 7 8 9 10 11 #使用下面的命令可以创建一个project django-admin.py startproject mysite #创…

xml解析-jaxp添加结点

jaxp添加结点 eg&#xff1a; //在第一个下面添加nv / 1.创建解析器工厂 * 2.根据解析器工厂创建解析器 * 3.解析xml返回document * * 4.得到第一个p1 * -得到所有p1使用item方法得到第一个p1 * * 5.创建sex标签 createElement * 6.创建文本 createTextNode * 7.把文本添加到se…

leetcode107. 二叉树的层次遍历 II

给定一个二叉树&#xff0c;返回其节点值自底向上的层次遍历。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&#xff09;例如&#xff1a; 给定二叉树 [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回其自底向上的层次遍历为&#xff1a…

javascript 图表_JavaScript 2018年的三个有争议的图表

javascript 图表by Sacha Greif由Sacha Greif JavaScript 2018年的三个有争议的图表 (Three Controversial Charts From the State of JavaScript 2018) 您认为统计数据和图表很无聊吗&#xff1f; 再想一想… (You thought stats and graphs were boring? Think again…) “…

签入在服务器上之后,别人获取了,在解决方案资源管理器中找不到。

签入在服务器上之后&#xff0c;别人获取了&#xff0c;在解决方案资源管理器中找不到。 这个问题具体原因我也不太清楚&#xff0c;但是我找到了一个解决方案。直接在解决方案上右键&#xff0c;添加&#xff0c;添加现有项。把在解决方案资源管理器上看不见的选中&#xff0c…

03JavaScript程序设计修炼之道-2019-06-20_20-31-49

## DomDocument object model 文档对象模型Dom树html|head body| |meta title div|ul|li li li在js世界中&#xff0c;把dom树的每个元素都看成一个对象&#xff0c;对象就有属性和方法dom学什么 dom节点操作 查找元素 元素增删改查 样式操作 事件绑定等## 事件三要素 1 事件源…

linux 独占 cpu,宋宝华:谈一谈Linux让实时 高性能任务独占CPU的事

本文主要讨论在高实时要求、高效能计算、DPDK等领域&#xff0c;Linux如何让某一个线程排他性独占CPU&#xff1b;独占CPU涉及的线程、中断隔离原理&#xff1b;以及如何在排他性独占的状况下&#xff0c;甚至让系统的timer tick也不打断独占任务&#xff0c;从而实现最低的延迟…

leetcode347. 前 K 个高频元素(排序)

给定一个非空的整数数组&#xff0c;返回其中出现频率前 k 高的元素。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2] 示例 2: 输入: nums [1], k 1 输出: [1] 代码 class Solution {public int[] topKFrequent(int[] nums, int k) {Map<Integer,Integer>…

如何在React中从其父组件更改子组件的状态

by Johny Thomas约翰尼托马斯(Johny Thomas) 如何在React中从其父组件更改子组件的状态 (How to change the state of a child component from its parent in React) We will be building a simple React app which shows the real name of a superhero on a button click.我们…

vue-property-decorator 提供 OO 的风格 Vue Component 方便类型声明

Prop 父子组件之间传值 Install: npm install --save vue-property-decoratorChild: <template><div>{{fullMessage}}</div> </template><script lang"ts">import Vue from vue import {Component, Prop} from vue-property-decorato…