1

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

现在,这个 PPC 依赖于 Spring 上下文中处理加密/解密任务的另一个 bean。目前,这个 bean 必须在 Spring 上下文 XML 文件中使用“硬编码”的值进行配置。我想通过 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。然后,使用它读取的属性,初始化“加密器”bean。最后,使用它初始化“encryptedPlaceholder” bean,以供上下文中的所有其他项目使用。

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

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

那有意义吗?有什么我可以在这里做的(除了使用上下文感知的东西来解决问题)来完成这项工作,还是这只是 Spring 的限制?当我在做的时候,有没有更好的方法来解决这个我没有看到的?

谢谢,

道格

4

1 回答 1

2

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

通过添加对encrypterbean的引用,encryptedPlaceHolderencrypter进入了这个较早的阶段。encrypter在 BeanPostProcessor 创建阶段创建,该阶段发生在可以调用任何处理器之前 - 也就是说,在可以解析任何属性之前。

据我所知,您不能让 PropertyPlaceHolderConfigurer 处理作为另一个 PropertyPlaceHolderConfigurer 依赖项的 bean 的属性。

当我在做的时候,有没有更好的方法来解决这个我没有看到的?

[更新]

一种解决方案是让它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,也不需要对现有的加密器类进行任何更改。

于 2012-12-14T03:38:59.063 回答