如何向应用程序上下文中添加属性

20

我有一个独立的应用程序,该应用程序计算一个值(属性),然后启动Spring上下文。我的问题是如何将计算后的属性添加到Spring上下文中,以便我可以像从属性文件加载的属性一样使用它(@Value("${myCalculatedProperty}"))?

为了更好地说明:

public static void main(final String[] args) {
    String myCalculatedProperty = magicFunction();         
    AbstractApplicationContext appContext =
          new ClassPathXmlApplicationContext("applicationContext.xml");
    //How to add myCalculatedProperty to appContext (before starting the context)

    appContext.getBean(Process.class).start();
}

ApplicationContext.xml:

<bean id="propertyPlaceholderConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:*.properties" />
</bean>

<context:component-scan base-package="com.example.app"/>

这是一个 Spring 3.0 应用程序。

4个回答

29

在 Spring 3.1 中,你可以实现自己的 PropertySource,请参见:Spring 3.1 M1: 统一的属性管理

首先,创建你自己的 PropertySource 实现:

private static class CustomPropertySource extends PropertySource<String> {

    public CustomPropertySource() {super("custom");}

    @Override
    public String getProperty(String name) {
        if (name.equals("myCalculatedProperty")) {
            return magicFunction();  //you might cache it at will
        }
        return null;
    }
}

现在,在刷新应用程序上下文之前,请添加此PropertySource:

AbstractApplicationContext appContext =
    new ClassPathXmlApplicationContext(
        new String[] {"applicationContext.xml"}, false
    );
appContext.getEnvironment().getPropertySources().addLast(
   new CustomPropertySource()
);
appContext.refresh();

从现在开始,您可以在Spring中引用您的新属性:

<context:property-placeholder/>

<bean class="com.example.Process">
    <constructor-arg value="${myCalculatedProperty}"/>
</bean>

还可以与注解一起使用(记得添加<context:annotation-config/>):

@Value("${myCalculatedProperty}")
private String magic;

@PostConstruct
public void init() {
    System.out.println("Magic: " + magic);
}

@Ralph:不幸的是,没有。只是为了记录,我添加了完整的“PropertySource”示例实现。 - Tomasz Nurkiewicz
这实际上是有效的,但你必须确保使用的Spring版本(包括所有依赖项)晚于3.0,否则你将无法取得太大进展。特别要检查context.xml文件顶部的包含内容。 - user1071914
有人能为Spring Boot提供解决方案吗? - Pratik Shah
@PratikShah 自Spring 3.1以来,您可以在带有@Configuration的类中添加@PropertySource("classpath:path/to/classpath/application.properties")。如果您使用的是Java <= 7.x,则使用复数形式的@PropertiySources - coderatchet

8
您可以将计算出的值添加到系统属性中:
System.setProperty("placeHolderName", myCalculatedProperty);

2
但请注意,这种方式会禁用从应用程序外部使用启动参数轻松覆盖此属性的可能性(即-DplaceHolderName = someEnvSpecificValue)。我认为添加使用系统属性处理特定于环境的值的可能性,并且还有其他将自定义属性添加到上下文中的可能性,例如注册多个“PropertyPlaceholderConfigurer”。 - Roadrunner

3
如果您像您的示例一样控制ApplicationContext的创建,那么您总是可以添加一个BeanRegistryPostProcessor将第二个PropertyPlaceholderConfigurer添加到上下文中。它应该具有ignoreUnresolvablePlaceholders="true"order="1",仅使用Properties对象解决自定义计算属性。所有其他属性都应由应该具有order="2"的XML中的PropertyPlaceholderConfigurer解析。

0

你的myCalculatedProperty必须包含在一个属性文件中(这些文件由Spring的propertyPlaceholderConfigurer注入)。

编辑:只需使用setter,类似于以下内容

public static void main(final String[] args) {
    String myCalculatedProperty = magicFunction();         
    AbstractApplicationContext appContext =
          new ClassPathXmlApplicationContext("applicationContext.xml");

    Process p = appContext.getBean(Process.class);
    p.setMyCalculatedProperty(myCalculatedProperty);
    p.start();
}

这个方法可以运行,但我不想创建一个属性文件(因为每次应用程序运行时值都不同),我想要直接“注入”它们。 - Ralph
只需使用您的属性的setter,不需要? - ndeverge
我不理解最后的评论。在Spring上下文中使用的属性类似于普通属性(使用@Value)。我需要以某种方式在Spring上下文中声明它,这样Spring(PropertyPlaceholder)才能像从属性文件中加载的属性一样使用它。 - Ralph
我明白,但这并不能解决问题。如果这样做,我将需要搜索所有使用@Value注释的字段(其中一些是构造函数参数)。因此,最终这将使Spring过时。 - Ralph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接