在Spring Boot的application.properties中使用env变量

S M*_*S M 148 java mysql spring spring-mvc openshift

我们正在开发一个Spring Boot Web应用程序,我们使用的数据库是MySql ;

  • 我们的设置是我们首先在本地测试它(意味着我们需要在我们的PC上安装MySql);

  • 然后我们推向Bitbucket ;

  • Jenkins自动检测到对Bitbucket的新推送并对其进行构建(对于Jenkins mvn构建要通过,我们还需要在运行Jenkins的虚拟机上安装MySql).

  • 如果Jenkins构建了传递,我们将代码推送到OpenShift上的应用程序(使用Jenkins上的Openshift部署插件).

我们可能已经弄明白的问题是:

  • application.properties我们不能硬编码MySql信息.由于我们的项目将在3个不同的地方运行(本地,JenkinsOpenShift),我们需要使数据源字段动态化application.properties(我们知道有不同的方法,但我们现在正在研究这个解决方案).

    spring.datasource.url = 
    spring.datasource.username = 
    spring.datasource.password = 
    
    Run Code Online (Sandbox Code Playgroud)

我们提出的解决方案是在本地和Jenkins vm中创建系统环境变量(以与OpenShift命名的方式命名它们)并分别为它们分配正确的值:

export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"
Run Code Online (Sandbox Code Playgroud)

我们做到了这一点并且有效.我们还检查Map<String, String> env = System.getenv();过环境变量可以变成java变量:

String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD");   
String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME");   
String sqlURL = env.get("OPENSHIFT_MYSQL_DB_HOST"); 
String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT");
Run Code Online (Sandbox Code Playgroud)

现在唯一剩下的就是我们需要在我们中使用这些java变量application.properties,这就是我们遇到的问题.

在哪个文件夹,以及我们如何,需要分配password,userName,sqlURL,和sqlPort变量application.properties能够看到他们,我们如何将它们包含在application.properties

我们尝试了很多其中一件事:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}
Run Code Online (Sandbox Code Playgroud)

到目前为止没有运气.我们可能没有将这些env变量放在正确的类/文件夹中,或者正确使用它们application.properties.

非常感谢您的帮助!!

谢谢!

Ken*_*kov 182

您不需要使用java变量.要包含系统env变量,请将以下内容添加到您的application.properties文件中:

spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD}
Run Code Online (Sandbox Code Playgroud)

但是@Stefan Isele建议的方式更可取,因为在这种情况下你只需声明一个env变量:spring.profiles.active.Spring将通过application-{profile-name}.properties模板自动读取相应的属性文件.

  • 我想补充一点,并提一下如果你使用spring boot(没有检查它是否在没有启动的情况下工作),那么任何属性都可以通过环境变量自动覆盖,而无需修改application.properties.即,如果你有一个名为`spring.activemq.broker-url`的属性,那么相应的环境变量将是:`SPRING_ACTIVEMQ_BROKER_URL`.句点和短划线会自动转换为下划线.使用容器/弹簧靴时非常方便. (27认同)
  • 这绝对是最好的方式.使用环境变量意味着您不需要在应用程序旁边以纯文本列出机密.这显然更加安全,并减少了对源代码访问安全措施的依赖性,以保护您的整个财产.包含属性的意外SO帖子不会导致信息泄露. (10认同)
  • 这种方法对于docker链接更方便.例如:`docker run --name my-tomcat -p 127.0.0.1:8080:8080 -e APP_DB_DB = mydb -e APP_DB_USER = dbuser -e APP_DB_PASS = dbpass --link mongo-myapp:mongo -v/path-to/tomcat/webapps:/ usr/local/tomcat/webapps -d tomcat:8-jre8-alpine` (8认同)
  • 如果您为云设计它并不是使用Spring配置文件的首选方式.12因素应用程序标准推荐使用环境变量:https://12factor.net/config (7认同)
  • 我知道这个话题有点老了。但是,您可以将环境变量设置和弹簧轮廓设置结合在一起。开发配置文件应该具有静态信息,而生产配置文件可以使用环境变量。这样,如果开发人员只想部署开发配置文件,则不再需要在其计算机上定义环境变量。 (5认同)
  • 找到我的自己http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-placeholders-in-properties (4认同)
  • @abe 感谢您提供信息。我检查了 spring 文档,这取决于你如何注入环境变量。根据 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-vs-value,`@value`不支持灵活绑定,但 `ConfigurationProperties` 可以按照你的描述做。 (2认同)
  • 这里有一个不幸的问题:如果 Spring Boot 找不到占位符指定的环境变量,它会默默地让占位符保持未展开状态。 (2认同)

Ste*_*com 57

对不同环境进行不同配置的最简单方法是使用弹簧轮廓.请参阅外部化配置.

这为您提供了很大的灵活性,我在我的项目中使用它并且它非常有用.在你的情况下,你将有3个配置文件'本地','jenkins'和'openshift'

然后,您有3个配置文件特定属性文件 application-local.properties application-jenkins.properties application-openshift.properties

在那里,您可以设置相关环境的属性.当您运行应用程序时,您必须指定要激活的配置文件 -Dspring.profiles.active=jenkins

编辑

根据spring doc,您只需要设置OS环境变量SPRING_PROFILES_ACTIVE来激活配置文件,而不是将其作为参数传递.

有没有办法在运行时为Web应用程序传递活动配置文件选项?

在构建应用程序上下文时,Spring将活动配置文件确定为第一步.然后使用活动配置文件来确定读取哪些属性文件以及实例化哪些bean.应用程序启动后,无法更改.

  • 虽然Spring配置文件非常有用,但与OP相比它们并不合适.这是由于源代码的存储方式以及存储的属性信息的敏感性.OP上下文围绕数据库访问.对于这种情况,您不希望源中的纯文本中的prod详细信息.这意味着如果源被泄露,那么数据库也会受到损害.最好使用env变量或秘密工具,例如Vault.我更喜欢环境.在这方面,我还要使所有环境以相同的方式运行以保持一致性.它可以避免将来发生事故. (8认同)
  • 谢谢你的回答Stefan,它对我有用,但有一个改变 - 该属性实际上是spring.profiles.active而不是spring.active.profiles (4认同)
  • 我喜欢这个答案,但是如果您希望配置文件名称来自环境怎么办?我已经尝试过-Dspring.active.profiles = $ SPRING_ACTIVE_PROFILES,并在/etc/profile.d/myenvvars.sh中设置OS env var,但是Spring Boot不会选择 (2认同)
  • 由于 spring boot http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-relaxed-捆绑 (2认同)
  • 您可以使用应用程序 JAR 外部的 Spring Boot 配置文件属性文件。这个特定于环境的文件,例如“application-production.properties”,将以安全的方式部署到生产机器上,并且通常不会在应用程序源代码存储库中。 (2认同)

小智 8

这是对一些评论的回应,因为我的声誉不足以直接评论.

只要尚未加载应用程序上下文,您就可以在运行时指定配置文件.

// Previous answers incorrectly used "spring.active.profiles" instead of
// "spring.profiles.active" (as noted in the comments).
// Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake.

System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment);
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
Run Code Online (Sandbox Code Playgroud)


Fel*_*tti 6

Flayway无法将直接环境变量识别到application.properties(Spring-Boot V2.1)中。例如

spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我做了这个环境变量,通常我创建文件.env:

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root
Run Code Online (Sandbox Code Playgroud)

并将变量导出到我的环境中:

export $(cat .env | xargs)
Run Code Online (Sandbox Code Playgroud)

最后只需运行命令

mvn spring-boot:run
Run Code Online (Sandbox Code Playgroud)

或运行您的jar文件

java -jar target/your-file.jar
Run Code Online (Sandbox Code Playgroud)

这里还有另一种方法:https : //docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html

  • 什么是环境变量?它们是如何使用的。您的答案涉及没有完整描述的事物,并且您不包含任何链接。我几乎对此投了反对票,但我看到你的代表是 21,所以你是新人,并且有人发现你的答案有用,所以我放弃了它,但尝试在未来的答案中提供更多信息,欢迎来到 SO(Stack Overflow)。我希望你和我一样喜欢它。 (3认同)
  • 谢谢@PatS,我添加了更多细节,希望它会有用。 (2认同)

Aja*_*mar 5

是通过一系列环境属性文件的片段代码,这些文件针对不同的环境进行加载。

应用程序资源(src / main / resources)下的属性文件:

 1. application.properties
 2. application-dev.properties
 3. application-uat.properties
 4. application-prod.properties
Run Code Online (Sandbox Code Playgroud)

理想情况下,application.properties包含所有环境都可以访问的所有公共属性,并且与环境相关的属性仅在指定环境下有效。因此,加载这些属性文件的顺序将是这种方式-

 application.properties -> application.{spring.profiles.active}.properties.
Run Code Online (Sandbox Code Playgroud)

此处的代码段:-

    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;

    public class PropertiesUtils {

        public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

        public static void initProperties() {
            String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE);
            if (activeProfile == null) {
                activeProfile = "dev";
            }
            PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer
                    = new PropertySourcesPlaceholderConfigurer();
            Resource[] resources = new ClassPathResource[]
                    {new ClassPathResource("application.properties"),
                            new ClassPathResource("application-" + activeProfile + ".properties")};
            propertySourcesPlaceholderConfigurer.setLocations(resources);

        }
    }
Run Code Online (Sandbox Code Playgroud)

  • Spring Boot 不是可以开箱即用地处理这种情况吗?请参阅[外部配置文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-特定属性) (3认同)

Abd*_*ala 5

使用 Spring context 5.0 我已经通过以下注释成功实现了根据系统环境加载正确的属性文件

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:application-${MYENV:test}.properties")})
Run Code Online (Sandbox Code Playgroud)

这里 MYENV 值是从系统环境中读取的,如果系统环境不存在,则将加载默认的测试环境属性文件,如果我给出错误的 MYENV 值 - 它将无法启动应用程序。

注意:对于每个配置文件,您想要维护 - 您将需要创建一个 application-[profile].property 文件,虽然我使用 Spring context 5.0而不是 Spring boot - 我相信这也适用于 Spring 4.1


Mic*_*dis 5

我遇到了与问题作者相同的问题。对于我们在这个问题中的案例答案是不够的,因为我团队的每个成员都有不同的本地环境,我们肯定需要.gitignore具有不同数据库连接字符串和凭据的文件,因此人们不会提交公共文件错误地破坏其他人的数据库连接。

最重要的是,当我们按照下面的过程进行操作时,它很容易部署在不同的环境中,而且作为额外的好处,我们根本不需要在版本控制中包含任何敏感信息

从具有parameters.yml(.gitignored) 和parameters.yml.dist(这是创建第一个到composer install)的示例的PHP Symfony 3 框架中获取想法,

我结合以下答案中的知识做了以下操作:https : //stackoverflow.com/a/35534970/986160/sf/answers/2487459691/

本质上,这提供了使用spring 配置继承的自由,并通过顶部的配置以及任何额外的敏感凭据选择活动配置文件,如下所示:

application.yml.dist(示例)

    spring:
      profiles:
        active: local/dev/prod
      datasource:
        username:
        password:
        url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
Run Code Online (Sandbox Code Playgroud)

application.yml(开发服务器上的 .gitignore-d)

spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: verysecretpassword
    url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
Run Code Online (Sandbox Code Playgroud)

application.yml (.gitignore-d 在本地机器上)

spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: rootroot
    url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
Run Code Online (Sandbox Code Playgroud)

application-dev.yml(不敏感的额外环境特定属性)

spring:
  datasource:
    testWhileIdle: true
    validationQuery: SELECT 1
  jpa:
    show-sql: true
    format-sql: true
    hibernate:
      ddl-auto: create-droop
      naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL57InnoDBDialect
Run Code Online (Sandbox Code Playgroud)

同样可以用 .properties 来完成