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.pswp.cn/news/393030.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/393030.shtml
英文地址,請注明出處:http://en.pswp.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…