【问题标题】:Creating a singleton bean using runtime parameters使用运行时参数创建单例 bean
【发布时间】:2014-03-29 18:43:03
【问题描述】:

我是 Spring 框架的新手,找不到实现以下目标的方法:

我正在使用一个属性都是私有的并且没有设置器的类(使用该类的对象的预期方法是使用构造函数设置一次属性) - 我将其称为 Preferences时间>。我还有一些类,每个类都具有相同的 Preferences 实例作为属性。 Preferences 旨在包含某些属性,其中一些只能在运​​行时解析(例如,由用户提供)。

在我的 .xml 文件中,我会写如下内容:

<bean id="preferenes" class="Preferences" scope="singleton">
    <constructor-arg index="0" value="defaultAttrOne" />
    <constructor-arg index="1" value="defaultAttrTwo" />
    <constructor-arg index="2" value="defaultAttrThree" />
</bean>

<bean id="someOtherBean" class="SomeOtherClass" scope="singleton">
    <constructor-arg index="0" ref="preferences" />
</bean>

也就是说,我可以提供默认值并在运行时将其中一些替换为自定义值。由于我无法修改 Preferences 的现有实例的属性,因此我必须构造一个新对象并以某种方式使 SomeOtherClass 的实例指向该新对象(这可以通过 bean 机制实现吗?)。

相反,我会在实例化任何 bean 之前将所需的运行时构造函数参数传递给 preferences bean(这些参数将在第一次调用 ApplicationContext 的构造函数之前知道)。我知道有一种 getBean() 方法的风格,它将可变参数作为初始化参数,尽管它仅适用于原型 bean。在这种情况下,我想初始化一次 Preferenes 并让所有帮助程序类都引用该单个实例。

感谢您的任何提示。

【问题讨论】:

  • 使用属性解析。
  • 您介意再详细说明一下吗?
  • 使用属性占位符${somePropertyName} 并配置PropertyPlaceholderConfigurer。然后在刷新ApplicationContext之前在运行时添加属性。

标签: java spring dependency-injection


【解决方案1】:

这几乎就是 Spring 默认为你做的事情,所以你不必做任何特别的事情:如果你创建了那个单例 bean 引用(称为preferences),你就可以将它注入到任何如您所料的其他豆子。

关于使用默认值的属性,有几种方法可以实现:

常规 XML 配置

如果需要,您可以保留纯基于 XML 的配置,并使用默认值配置 PropertyPlaceholderConfigurer。比如:

<bean class="org.s.beans.factory.config.PropertyPlaceholderConfigurer">      
    <property name="location" value="prefrences.properties"/>
</bean>

<bean id="preferenes" class="Preferences" scope="singleton">
   <constructor-arg index="0" value="$[preferences.one:12]" />
   <constructor-arg index="1" value="$[preferences.two:AUTO]" />
   <constructor-arg index="2" value="$[preferences.three:false]" />
</bean>

如果您不想要默认值,请在类路径的根目录中使用 prefrences.properties 来保存特定值

prefrences.three=true

工厂豆

由于您已经在使用 XML,您可以使用 FactoryBean 来创建 Preferences 实例,类似于

<bean id="preferences" class="org.myproject.PreferencesFactoryBean"/>

在工厂代码中,您可以使用任何您想要检索配置的非默认值的机制,包括注入自定义属性。

Java 配置

您也可以采用 java config 方式,但由于您是初学者,这可能会有所改变。但是,java config 确实强大且灵活,因此您可能想尝试一下。

@Configuration
@PropertySource("classpath:preferences.properties")
public class AppConfig {

    @Value("${preferences.one}")
    private int preferenceOne = 12;

    @Value("${preferences.two}")
    private MyEnum preferenceTwo = MyEnum.AUTO;

    @Value("${preferences.three}")
    private boolean preferenceThree;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public Preferences preferences() {
        return new Preferences(preferenceOne, preferenceTwo, preferenceThree);
    }

}

【讨论】:

  • 感谢您的帮助,尽管这仍然不是我想要实现的目标。我想传递给 Preferences bean 的参数不驻留在属性文件中(也许我在我的问题中误用了“属性”这个词)。相反,它们将在代码级别提供,并且可以是某些自定义类的实例。坚持注释约定,我将有一个 @Value("${myClass}") 注释的 MyClass myClass 字段,供首选项 bean 使用(如上面的示例)。从配置类外部,我想先设置 myClass 字段,然后调用 getBean(Preferences.class)。
  • 你不能那样做。这就像如果你想管理一个对象状态,然后要求 Spring 来处理它。这就是为什么过去通过属性文件等声明性方式提供此类内容的原因,因为容器管理它。话虽如此,我上面提供给你的任何东西都没有错。您可以创建一个 FactoryBean 并在 getObject 中拥有您想要的所有逻辑。对于 Java 配置(第三个示例),您可以在 preferences() 中调用您需要的任何内容并删除 @Value 字段
猜你喜欢
  • 2013-02-07
  • 1970-01-01
  • 2014-04-05
  • 2015-01-14
  • 2022-07-28
  • 1970-01-01
  • 2019-12-21
  • 1970-01-01
  • 2014-09-19
相关资源
最近更新 更多