從原始碼分析Spring處理property-placeholder原理
一、如何在Spring中將屬性檔案配置內容載入到環境中
1.1、在Spring的XML配置檔案中配置<context:property-placeholder/>,由於<context:property-placeholder/>名稱空間為
http://www.springframework.org/schema/context,通過名稱空間名與處理程式的對映關係(Sping中配置的關係在sping.handlers檔案中),
找到處理器http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
1.2、在ContextNamespaceHandler中的init()函式中註冊了parser解析器this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
1.3、呼叫PropertyPlaceholderBeanDefinitionParser.parse()函式開始解析XML中配置的屬性
1.4、在PropertyPlaceholderBeanDefinitionParser.parse()函式中呼叫了AbstractSingleBeanDefinitionParser.parseInternal()函式構建
構建內部BeanDefinition,最後呼叫了AbstractPropertyLoadingBeanDefinitionParser.doParse()函式解析property-placeholder自定義的屬性
1.5、最後將構建好的BeanDefinition註冊到BeanDefinitionRegistry註冊中心中供Spring上下文使用
二、如何使用載入到環境中的配置
2.1、Spring通過BeanFactoryProcessor進行擴充套件,Spring提供了PropertyPlaceholderConfigurer(其實現了BeanFactoryPostProcessor)
在Bean建立前將佔位符使用配置檔案中的配置值替換
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
或者
@Value("${spring_only}")
private String springOnly;
2.2、通過兩種方式注入
Bean方式:
單個配置檔案
<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location">
<value>conf/sqlmap/jdbc.properties</value>
</property>
<property name="fileEncoding">
<value>UTF-8</value>
</property>
</bean>
多個配置檔案
<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/mail.properties</value>
<value>classpath: conf/sqlmap/jdbc.properties</value>//注意這兩種value值的寫法
</list>
</property>
</bean>
標籤方式:
<context:property-placeholder location="classpath*:/WEB-INF/mail.properties" />
今天一個問題困擾了我一下午,因此必須記錄下來
在PropertyPlaceholderConfigurer類中的location、locations、localProperties分別為 Resource、Resource[]、Properties[]型別,
而XML中指定屬性值時卻是字串型別,一直都不知道Spring在什麼時候、通過哪種機制處理轉換的(將字串轉換成Resource、Resource[]、Properties[])
研究了很久發現Spring提供了一些系統的屬性編輯器(超類為PropertyEditorSupport),Spring在解析和賦值property時,會呼叫對應的編輯器處理
,且Spring會預設依據property的型別找對應的編輯器。比如Resource有對應的編輯器ResourceEditor,會將字串值轉換處理為Resource、Resource[]。
若想要改變預設的PropertyEditor,可以新增自定義的來覆蓋它。在新增時可以使用一個自動檢測的機制:也就是需要遵照一定的規則
具體的規則是:PropertyEditor類和標準的 JavaBeans在同一個包下,並且他們PropertyEditor的類名是JavaBeans的類名加上“Editor”,比如:
- publicclass ExoticTypeEditor extends PropertyEditorSupport {
- publicvoid setAsText(String text) {
- setValue(new ExoticType(text.toUpperCase()));
- }
- }
可以看到這個PropertyEditor就是遵照了以上的命名規則,並且和ExoticType放在同一個包中,所以無需額外的配置就可以得到下面的輸出:
ANAMEFOREXOTICTYPE
那麼若沒有符合以上規則的話,怎麼辦呢?可以通過org.springframework.beans.factory.config.CustomEditorConfigurer這個Bean來註冊
為這個Bean配置customEditors屬性,該屬性是一個Map,將我們需要註冊的PropertyEditors都注入到這個Map裡就可以了:
- <beanclass="org.springframework.beans.factory.config.CustomEditorConfigurer">
- <propertyname="customEditors">
- <map>
- <entrykey="document.six.test.ExoticType"value="document.six.test.ExoticType2Editor"/>
- </map>
- </property>
- </bean>