java 可选的@PropertySource 位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17401583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 01:54:49  来源:igfitidea点击:

Optional @PropertySource location

javaspringspring-annotations

提问by Gerhard Schlager

I'm using Spring 3.2 in a web application and I'd like to have a .propertiesfile within the classpath which contains default values. The user should be able to use JNDI to define a location where another .propertiesis stored which overrides the default values.

我在 Web 应用程序中使用 Spring 3.2,并且我希望.properties在类路径中有一个包含默认值的文件。用户应该能够使用 JNDI 来定义.properties存储另一个覆盖默认值的位置。

The following works as long as the user has set the configLocationas JNDI property.

只要用户设置了configLocationas JNDI 属性,以下就可以工作。

@Configuration
@PropertySource({ "classpath:default.properties", "file:${java:comp/env/configLocation}/override.properties" })
public class AppConfig
{
}

However, the external overrides should be optional and so should the JNDI property.

但是,外部覆盖应该是可选的,JNDI 属性也应该是可选的。

Currently I get an exception (java.io.FileNotFoundException: comp\env\configLocation\app.properties (The system cannot find the path specified)when the JNDI property is missing.

目前我得到一个异常(java.io.FileNotFoundException: comp\env\configLocation\app.properties (The system cannot find the path specified)当 JNDI 属性丢失时。

How can I define optional .propertiesthat are used only when the JNDI property (configLocation) is set? Is this even possible with @PropertySourceor is there another solution?

如何定义.properties仅在设置 JNDI 属性 ( configLocation)时使用的可选?这甚至可能@PropertySource还是有其他解决方案?

采纳答案by vivo

Try the following. Create a ApplicationContextInitializer

请尝试以下操作。创建一个ApplicationContextInitializer

In a Web Context: ApplicationContextInitializer<ConfigurableWebApplicationContext>and register it in the web.xml via:

在 Web 上下文中:ApplicationContextInitializer<ConfigurableWebApplicationContext>并通过以下方式在 web.xml 中注册它:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>...ContextInitializer</param-value>
</context-param>

In the ContextInitializer you can add your property files via classpath and file system (haven't tried JNDI though).

在 ContextInitializer 中,您可以通过类路径和文件系统添加属性文件(不过还没有尝试过 JNDI)。

  public void initialize(ConfigurableWebApplicationContext applicationContext) {
    String activeProfileName = null;
    String location = null;

    try {
      ConfigurableEnvironment environment = applicationContext.getEnvironment();
      String appconfigDir = environment.getProperty(APPCONFIG);
      if (appconfigDir == null ) {
        logger.error("missing property: " + APPCONFIG);
        appconfigDir = "/tmp";
      }
      String[] activeProfiles = environment.getActiveProfiles();

      for ( int i = 0; i < activeProfiles.length; i++ ) {
        activeProfileName = activeProfiles[i];
        MutablePropertySources propertySources = environment.getPropertySources();
        location = "file://" + appconfigDir + activeProfileName + ".properties";
        addPropertySource(applicationContext, activeProfileName,
                location, propertySources);
        location = "classpath:/" + activeProfileName + ".properties";
        addPropertySource(applicationContext, activeProfileName,
                          location, propertySources);
      }
      logger.debug("environment: '{}'", environment.getProperty("env"));

    } catch (IOException e) {
      logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location);
      e.printStackTrace();
    }
  }

  private void addPropertySource(ConfigurableWebApplicationContext applicationContext, String activeProfileName,
                                 String location, MutablePropertySources propertySources) throws IOException {
    Resource resource = applicationContext.getResource(location);
    if ( resource.exists() ) {
      ResourcePropertySource propertySource = new ResourcePropertySource(location);
      propertySources.addLast(propertySource);
    } else {
      logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location);
    }
  }

The code above tries to find a property file per active profile (see: How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property)

上面的代码尝试为每个活动配置文件查找一个属性文件(请参阅:如何通过属性文件而不是通过 env 变量或系统属性设置活动的 spring 3.1 环境配置文件

回答by matsev

As of Spring 4, issue SPR-8371has been solved. Consequently, the @PropertySourceannotation has a new attribute called ignoreResourceNotFoundthat has been added for exactly this purpose. Additionally, there is also the new @PropertySourcesannotation which allows implementations like:

从 Spring 4 开始,问题SPR-8371已经解决。因此,@PropertySource注释有一个名为的新属性ignoreResourceNotFound,正是为此目的而添加的。此外,还有新的@PropertySources注释,它允许实现如下:

@PropertySources({
    @PropertySource("classpath:default.properties"),
    @PropertySource(value = "file:/path_to_file/optional_override.properties", ignoreResourceNotFound = true)
})

回答by Koraktor

If you're not yet on Spring 4 (see matsev's solution), here's a more verbose, but roughly equivalent solution:

如果您还没有使用 Spring 4(请参阅 matsev 的解决方案),这里有一个更冗长但大致等效的解决方案:

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

    @Autowired
    public void addOptionalProperties(StandardEnvironment environment) {
        try {
            String localPropertiesPath = environment.resolvePlaceholders("file:${java:comp/env/configLocation}/override.properties");
            ResourcePropertySource localPropertySource = new ResourcePropertySource(localPropertiesPath);
            environment.getPropertySources().addLast(localPropertySource);
        } catch (IOException ignored) {}
    }

}