PropertyPlaceholderConfigurers 的初始化顺序(Spring 3) [英] Initialization order of PropertyPlaceholderConfigurers (Spring 3)

查看:95
本文介绍了PropertyPlaceholderConfigurers 的初始化顺序(Spring 3)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my Spring-based web application, I need to store encrypted values in a properties file. To this end, I have subclassed the Spring "PropertyPlaceholderConfigurer" class, and overridden its "convertProperties" method so that after loading properties from a file, it decrypts those that are encrypted. This works great.

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

Now, this PPC depends on another bean in the Spring context that handles the encryption/decryption duties. Presently, this bean has to be configured with values "hard coded" in the Spring context XML file. I wanted to have these values pulled from the properties file via the PPC, but then doing so creates a circular dependency (the decrypter can't receive info from the PPC that needs the decrypter to do its job...).

所以...我以为我会做的是创建 2 个属性文件:一个用于加密内容,另一个用于明文内容.然后,我将创建两个 PPC - 一个正常的,一个我的子类设计来处理加密内容.这样,我就可以将解密器的配置选项放入明文属性文件中!

SO... what I thought I would do is create 2 properties files: one for encrypted stuff and the other for clear text stuff. Then, I would create two PPCs - one normal, and one of my subclassed design to handle the encrypted contents. That way, I could put the decrypter's configuration options into the clear text properties file!

不幸的是,我似乎对 Spring 初始化项目的顺序有问题.这是我在 XML 中的设置示例:

Unfortunately, I seem to be having a problem with the order in which items are initialized by Spring. Here's an example of my setup in 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 以供上下文中的所有其他项目使用.

So in this case, I'd like Spring to first initialize the "clearTextPlaceholder" bean. Then, using the properties that it reads in, initialize the "encrypter" bean. And finally, using that, initialize the "encryptedPlaceholder" bean for use by all other items in the context.

然而,真正发生的事情是在启动时,加密器"bean 被传递了一个文字${plain-text-property}"字符串,然后,两个 PPC 都初始化(或尝试,在它失败之前由于加密器 bean 配置不当).

However, what really happens is that at startup, the "encrypter" bean gets passed a literal "${plain-text-property}" string, and THEN, both of the PPCs initialize (or try to, before it fails due to a badly configured encrypter bean).

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

I have tried adding the "depends-on" attribute to the relevant beans to enforce an initialization order, but to no avail. It seems like Spring wants to go ahead and create ALL of the defined PPCs at once, and since ONE of them depends on another bean, that means BOTH of them have to wait until that other bean is initialized.

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

Does that make sense? Is there anything I can do here (short of getting down in the weeds with context-aware stuff) to make this work, or is this just a limitation of Spring? And while I'm at it, is there a better way to go about this that I'm not seeing?

谢谢,

道格

推荐答案

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

I reproduced your situation - and yes it works exactly as you described. Both of your PropertyPlaceHolderConfigurers are BeanPostProcessors. During startup, Spring creates all the BeanPostProcessor beans. Then it invokes them. You can change the order of invocation by setting the order property. However it always finishes the creation of all the processors - even the lowest priority - before invoking any of them.

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

By adding a reference of the encrypter bean to the encryptedPlaceHolder you moved encrypter into this earlier phase. encrypter is created during the BeanPostProcessor creation phase which happens before any processor can be invoked - that is, before any properties can be resolved.

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

As far as I can see, you cannot have a PropertyPlaceHolderConfigurer process the properties of a bean which is a dependency of another PropertyPlaceHolderConfigurer.

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

And while I'm at it, is there a better way to go about this that I'm not seeing?

[更新]

一种解决方案是使 encrypter 足够智能以直接读取属性文件.更依赖注入友好"的方法是创建自定义工厂 bean.参考 http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-class-instance-factory-method

One solution is to make encrypter smart enough to read the property file directly. A more "dependency injection friendly" way would be to create a custom factory bean. For reference see 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 可能看起来像:

The factory bean might look like:

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,也不需要对现有的加密器类进行更改.

Even though you would have to create a new, special purpose factory bean, no changes are required to your existing encrypter class.

这篇关于PropertyPlaceholderConfigurers 的初始化顺序(Spring 3)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆