2012-12-14 127 views
0

在我的基於Spring的Web應用程序中,我需要將加密值存儲在屬性文件中。爲此,我創建了Spring「PropertyPlaceholderConfigurer」類,並重寫了其「convertProperties」方法,以便在從文件加載屬性後,解密那些經過加密的屬性。這很好。PropertyPlaceholderConfigurers(Spring 3)的初始化順序

現在,這個PPC依賴於處理加密/解密職責的Spring上下文中的另一個bean。目前,這個bean必須在Spring上下文XML文件中配置值「硬編碼」。我希望通過PPC從屬性文件中提取這些值,但這樣做會產生循環依賴(解密器無法從PPC獲得需要解密器完成其工作的信息...)。

所以我想我會做的是創建2個屬性文件:一個用於加密的東西,另一個用於明文的東西。然後,我將創建兩個PPC--一個普通的PPC和一個用於處理加密內容的子類設計。這樣,我可以將解密器的配置選項放入明文屬性文件中!

不幸的是,我似乎遇到了Spring初始化項目的順序問題。這是我設置的實例,在XML:

<bean id="clearTextPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="ignoreUnresolvablePlaceholders" value="true" /> 
    <property name="location" value="clear.properties" /> 
</bean> 

<bean id="encryptedPlaceholder" class="com.mycompany.EncryptedPlaceholderConfigurer"> 
    <property name="ignoreUnresolvablePlaceholders" value="true" /> 
    <property name="location" value="encrypted.properties" /> 
    <property name="encryption" ref="encrypter" /> 
</bean> 

<bean id="encrypter" class="com.mycompany.Encrypter"> 
    <property name="someOption" value="${plain-text-property}" /> 
</bean> 

因此,在這種情況下,我想春天先初始化「clearTextPlaceholder」豆。然後,使用它讀入的屬性,初始化「加密器」bean。最後,使用它初始化「encryptedPlaceholder」bean以供上下文中的所有其他項使用。

然而,真正發生的情況是,在啓動時,「encrypter」bean傳遞一個字面的「$ {plain-text-property}」字符串,然後,這兩個PPC都會初始化(或嘗試)由於配置錯誤的加密器bean而失敗)。

我曾嘗試將「依賴」屬性添加到相關的bean來強制執行初始化順序,但無濟於事。 Spring似乎希望繼續創建所有已定義的PPC,並且由於其中一個依賴於另一個bean,這意味着它們都必須等到其他bean被初始化。

這有道理嗎?有什麼我可以在這裏做的(通過上下文感知的東西來遏制雜草)來完成這項工作,或者這只是Spring的限制嗎?雖然我在這裏,有沒有更好的方式去做這件事,我沒有看到?

感謝,

道格

回答

1

我複製你的情況 - 是它的工作原理完全像你描述。兩個PropertyPlaceHolderConfigurers都是BeanPostProcessors。在啓動過程中,Spring創建所有BeanPostProcessor bean。然後它調用它們。您可以通過設置order屬性來更改調用的順序。然而,在調用任何處理器之前,它總是完成所有處理器的創建 - 即使是最低優先級 - 也是如此。

通過將encrypter bean的引用添加到encryptedPlaceHolder中,您將encrypter移至此早期階段。 encrypter是在BeanPostProcessor創建階段創建的,這個階段在調用任何處理器之前發生 - 也就是說,在任何屬性都可以解析之前。

據我所見,你不能有一個PropertyPlaceHolderConfigurer進程的bean的屬性,這是另一個PropertyPlaceHolderConfigurer的依賴關係。

雖然我在這裏,有沒有更好的方式去做這件事,我沒有看到?

[更新]

一種解決方案是讓encrypter足夠聰明,直接讀取屬性文件。更「依賴注入友好」的方式是創建一個自定義工廠bean。更多信息參見http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-class-instance-factory-method

<bean id="encrypter" factory-bean="encrypterFactory" factory-method="createInstance"> 
</bean> 

<bean id="encrypterFactory" class="com.mycompany.EncrypterFactory" init-method="init"> 
    <property name="location" value="clear.properties"/> 
</bean> 

工廠bean可能看起來像:

public class EncrypterFactory 
{ 
    Properties properties; 
    File file; 

    public void setLocation(String fileName) 
    { 
     this.file = new File(fileName); 
    } 
    public void init() throws IOException 
    { 
     properties = new Properties(); 
     properties.load(new FileReader(file)); 
    } 

    public Encrypter createInstance() 
    { 
     Encrypter encrypter = new Encrypter(); 
     encrypter.setSomeOption(properties.getProperty("plain-text-property")); 
     return encrypter; 
    } 
} 

即使你需要創建一個新的,特殊用途的工廠bean,不需要更改您現有的加密類。

+0

好吧,我認爲必須是發生了什麼,考慮到結果。我只是希望我錯了! 我會像你說的那樣做,並且使「加密器」bean足夠聰明地處理屬性,除了它當前是一個用於許多其他事物的啞加密/解密管道,並且我寧願不專門做這麼多。雖然...如果我找不到更好的方法,我可能會做到這一點。 –

+0

@DouglasRapp - 一個很好的觀點。查看更新。 –

+0

優秀的解決方案 - 謝謝! –