PropertyPlaceholderConfigurers的初始化顺序(Spring 3)

时间:2012-12-14 00:41:54

标签: java spring properties

在我的基于Spring的Web应用程序中,我需要将加密值存储在属性文件中。为此,我已经将Spring“PropertyPlaceholderConfigurer”类子类化,并重写了它的“convertProperties”方法,以便在从文件加载属性后,它会解密那些加密的属性。这很有效。

现在,这个PPC依赖于处理加密/解密任务的Spring上下文中的另一个bean。目前,必须在Spring上下文XML文件中为此bean配置“硬编码”值。我希望通过PPC从属性文件中提取这些值,但这样做会产生循环依赖(解密器无法从PPC接收需要解密器完成其工作的信息......)。

所以...我认为我会做的是创建2个属性文件:一个用于加密的东西,另一个用于明文。然后,我将创建两个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>

所以在这种情况下,我希望Spring首先初始化“clearTextPlaceholder”bean。然后,使用它读入的属性,初始化“encrypter”bean。最后,使用它,初始化“encryptedPlaceholder”bean以供上下文中的所有其他项使用。

然而,真正发生的是,在启动时,“加密器”bean传递了文字“$ {plain-text-property}”字符串,然后,两个PPC在失败之前初始化(或尝试)由于配置错误的加密器bean。)

我尝试将“依赖”属性添加到相关bean以强制执行初始化顺序,但无济于事。看起来Spring想要继续创建所有已定义的PPC,并且由于其中一个依赖于另一个bean,这意味着它们必须等到其他bean被初始化。

这有意义吗?有什么我可以在这里做的(没有在具有上下文感知的东西的杂草中)使这项工作,或者这仅仅是Spring的限制?虽然我在这里,有没有更好的方法来解决这个问题,我没有看到?

谢谢,

道格

1 个答案:

答案 0 :(得分:1)

我重现了你的情况 - 是的,它完全按照你的描述工作。两个PropertyPlaceHolderConfigure都是BeanPostProcessors。在启动期间,Spring会创建所有BeanPostProcessor bean。然后它调用它们。您可以通过设置order属性来更改调用顺序。然而,在调用任何处理器之前,它总是完成所有处理器的创建 - 甚至是最低优先级。

通过将encrypter bean的引用添加到encryptedPlaceHolder,您将encrypter移动到此前一阶段。在BeanPostProcessor创建阶段创建encrypter,该阶段在任何处理器可以被调用之前发生 - 也就是说,在任何属性可以被解析之前。

据我所知,你不能让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,也不需要对现有的加密器类进行任何更改。