【问题标题】:Different property variable for Local and prod Environment (Spring)本地和产品环境(Spring)的不同属性变量
【发布时间】:2014-03-31 08:52:53
【问题描述】:

我正在开发一个 Spring Web 应用程序,在该应用程序中,我需要在本地环境中具有不同值和在生产环境中具有其他值的变量。

例如(文件上传目录)。我的文件上传目录对于本地和生产环境是不同的。

目前我通过检查主机名(如果是'localhost'然后是A,否则B)并采用这种方法来做到这一点。还有另一种通过属性文件解决这个问题的方法,有人给我指点如何解决这个问题吗?

【问题讨论】:

  • 您应该使用弹簧配置文件并根据当前活动配置文件加载属性文件。

标签: spring spring-mvc


【解决方案1】:

您可以根据当前的弹簧轮廓或轮廓加载属性。要设置弹簧轮廓,我主要将名为 spring.profiles.active 的系统属性设置为所需的值,例如developmentproduction

这个概念很简单。从系统属性中读取当前活动的配置文件。使用PropertySourcesPlaceholderConfigurer 构建文件名并加载属性文件。使用PropertySourcesPlaceholderConfigurer 将更容易通过@Value 注释访问这些属性。请注意,此示例假定一个配置文件处于活动状态。当多个配置文件处于活动状态时,它可能需要格外小心。

基于 Java 的配置

@Configuration
public class MyApplicationConfiguration {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        String activeProfile = System.getProperty("spring.profiles.active", "production");
        String propertiesFilename = "app-" + activeProfile + ".properties";

        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setLocation(new ClassPathResource(propertiesFilename));

        return configurer;
    }
}

您还可以导入多个使用@Profile 注释的配置类。 Spring 将根据当前活动的配置文件选择要使用的配置。每个类都可以将它自己的PropertySourcesPlaceholderConfigurer 版本添加到应用程序上下文中。

@Configuration
@Import({Development.class, Production.class})
public class MyApplicationConfiguration {}

@Configuration
@Profile("development")
public class Development {}

@Configuration
@Profile // The default
public class Production {}

正如 Emerson Farrugia 在他的评论中所说,@Profile 每班方法对于选择PropertySourcesPlaceholderConfigurer 有点过激。注释 @Bean 声明会简单得多。

@Configuration
public class MyApplicationConfiguration {

    @Bean
    @Profile("development")
    public static PropertySourcesPlaceholderConfigurer developmentPropertyPlaceholderConfigurer() {
        // instantiate and return configurer...
    }

    @Bean
    @Profile // The default
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        // instantiate and return configurer...
    }
}

【讨论】:

  • 如果意图是让单个Development 配置包含要在开发环境中注册的所有(不相关的)bean,那么第二个示例可能会导致混合问题。在 IMO 场景中,即在 PropertySourceConfiguration @Configuration 类中,最好用 @Profile 注释 @Bean 方法。
  • @Brat 谢谢你的回答,但我不清楚这部分“我主要将一个名为 spring.profiles.active 的系统属性设置为所需的值,例如开发或生产”你实际上在哪里设置这个?
  • 您可以在代码中设置系统属性(使用System.setProperty)、JVM 选项、JAVA_OPTS 等。对于测试用例,您可以使用@ActiveProfile 注释您的测试
  • @Bart,我应用了与您建议的相同的逻辑。我创建了两个文件 app-dev.properties 和 app-openshift.properties,并将它们保存在资源文件夹中。它在我的本地环境中运行良好,但无法在我部署战争的服务器上选择属性文件。我应该将文件保存在哪里?
  • @abhishekgaloda 阅读org.springframework.context.annotation.Profile的源码
【解决方案2】:

一个完全不涉及 Spring Profiles 的解决方案是使用类似以下的东西:

<context:property-placeholder location="classpath*:config.properties,file:/path/config/config.properties"
                              ignore-unresolvable="false" ignore-resource-not-found="true"/>

它的作用是告诉 Spring 使用两个文件查找属性,一个是 jar/war 中的文件,另一个是文件系统中任何位置的文件。 ignore-resource-not-found 意味着如果没有找到其中一个文件,Spring 不会抱怨。

使用此设置,第二个文件可以由 DevOps 人员控制,并且可以包含他们选择的任何内容,从而覆盖类路径属性文件文件中的任何属性。

更新:

您可以在配置类中使用以下 bean 对 Java Config 执行相同操作

@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
    final PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();

    Resource[] resources = new Resource[ ] {
            new ClassPathResource( "config.properties" ),
            new FileSystemResource("/path/config/config.properties")
    };

    pspc.setLocations( resources );
    pspc.setIgnoreResourceNotFound(true);
    pspc.setIgnoreUnresolvablePlaceholders(false);
    return pspc;
}

【讨论】:

  • @NielsBechNielsen 如果要加载额外的 XML 资源,可以使用 @ImportResource 注释配置类
  • @geoand 您的示例加载了多个文件。但它如何区分 OP 询问的环境?
  • @Bart 正如我在回答开头提到的,第二个路径是文件系统路径,其内容可以特定于部署应用程序的环境。在测试中 /path/config/config.properties 可能有 creditCard.bank.isProduction = false ,而在生产中它将是 creditCard.bank.isProduction = true 。这种设置有助于 DevOps 人员更有效地控制您的应用程序环境。
【解决方案3】:

我已经为此苦恼了半天,我最终得到的解决方案是这里的其他答案的组合。

Bart 的解决方案对我来说存在使用动态 prop 文件的缺点,因此我的 IDE “忘记”了它的所有内容,无法建议我使用了哪些属性以及在哪里使用。 Geoand 解决方案对我来说有一个缺点,即配置文件“应该在某个地方”。我可以理解为什么这在某些情况下很方便,但我倾向于在任何环境中部署一个可部署的单个工件,因此我不必将文件“停放”在战略位置以便应用程序拾取。

因此,我的解决方案是:

- config.properties (default properties, usually local development env)
- config.staging.properties (overrides depending on the env)
- config.prod.properties (overrides depending on the env)

<context:property-placeholder ignore-resource-not-found="true"
                              location="config.properties,
                                        config-${profile}.properties"/>

神奇的是ignore-resource-not-found="true",它允许我在不设置任何特殊profile 变量的情况下启动我的本地开发环境。丢失的文件将被忽略。

相反,我在各种部署环境中设置了该变量,例如-Dprofile=staging,然后会找到该文件并应用覆盖。

【讨论】:

    【解决方案4】:

    在我上面的情况下,任何解决方案都不起作用,所以我从我的最后做了一些谷歌,最后找到了一些可行的解决方案。

    我对上面的类做了如下修改:

    @Configuration
    @PropertySource("classpath:application-${spring.profiles.active}.properties")
    public class MyApplicationConfiguration {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        return configurer;
    }
    }
    

    而不是在方法内部定义动态文件名。我正在定义如下文件名,这对我来说很神奇。

    @PropertySource("classpath:application-${spring.profiles.active}.properties")

    在类的顶部。通过遵循 Bart 的解决方案,我没有收到任何错误,但我将所有属性都设置为在属性文件中定义的 null 值。

    通过使用我的方法,spring 能够识别在 VM 参数和环境变量中定义的属性。 注意:我使用的是非 Spring Boot 项目。

    【讨论】:

      【解决方案5】:

      当您启动服务器时,您可以在 Spring Boot 应用程序中添加 -Dspring.profile.active=local。它将选择 application-local.properties

      【讨论】:

        猜你喜欢
        • 2018-03-22
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 1970-01-01
        • 2016-11-07
        • 1970-01-01
        • 1970-01-01
        • 2019-01-23
        相关资源
        最近更新 更多