Spring Bootのapplication.propertiesでenv変数を使用する


199

私たちはSpring Boot Webアプリに取り組んでおり、使用しているデータベースはMySqlです。

  • 私たちの設定は、最初にローカルでテストすることです(つまり、PCにMySqlをインストールする必要があります)。

  • 次に、Bitbucketにプッシュします。

  • JenkinsはBitbucketへの新しいプッシュを自動的に検出し、それに基づいてビルドを実行します(Jenkins mvn buildをパスするには、Jenkinsを実行している仮想マシンにMySqlをインストールする必要もあります)。

  • Jenkinsビルドが成功した場合、OpenShiftのアプリケーションにコードをプッシュします(JenkinsのOpenshiftデプロイメントプラグインを使用)。

あなたがすでにそれを理解しているかもしれないので、私たちが抱えている問題は次のとおりです:

  • application.properties我々のハードコードMySQLの情報はできません。プロジェクトは3つの異なる場所(localJenkins、およびOpenShift)で実行されるため、データソースフィールドを動的にする必要がありますapplication.properties(これにはさまざまな方法があることはわかっていますが、今のところこのソリューションに取り組んでいます)。

    spring.datasource.url = 
    spring.datasource.username = 
    spring.datasource.password = 

私たちが思いついた解決策は、ローカルおよび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"

私たちはこれを実行し、それは機能します。また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");

今残っているのは、これらのJava変数を使用する必要があることだけですapplication.properties。それが問題です。

どのフォルダには、どのように、私たちが割り当てる必要がありませんpassworduserNamesqlURL、およびsqlPortのための変数application.propertiesにそれらを見て、どのように我々はそれらを含めないことができるようにするのapplication.properties

私たちはそれらの1つである多くのことを試みました:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}

これまでのところ運がありません。これらの環境変数を適切なクラス/フォルダに配置していないか、でそれらを誤って使用している可能性がありapplication.propertiesます。

あなたの助けは大歓迎です!!

ありがとう!


回答:


267

Java変数を使用する必要はありません。システム環境変数を含めるには、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}

ただし、@ Stefan Iseleによって提案された方法の方がより好ましいです。この場合、env変数を1つだけ宣言する必要があるためですspring.profiles.active。Springは適切なプロパティファイルをapplication-{profile-name}.propertiesテンプレートによって自動的に読み取ります。


12
この方法は、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
FıratKÜÇÜK

17
これは絶対に最善の方法です。環境変数を使用することで、アプリケーションと一緒にシークレットをプレーンテキストでリストする必要がなくなります。これにより、セキュリティが大幅に向上し、資産全体を保護するためのソースコードアクセスセキュリティ対策への依存が軽減されます。プロパティが含まれている誤ったSO投稿は、情報漏えいの原因にはなりません。
kipper_t 2017

51
これに追加して、スプリングブートを使用している場合(ブートなしで機能するかどうかを確認しなかった場合)は、application.propertiesを変更せずに、環境変数を介してすべてのプロパティを自動的にオーバーライドできることを述べました。つまり、呼び出されるプロパティがある場合spring.activemq.broker-url、対応する環境変数は次のようになりますSPRING_ACTIVEMQ_BROKER_URL。ピリオドとダッシュは自動的にアンダースコアに変換されます。これは、コンテナー/スプリングブートで作業するときに非常に便利です。
阿部

15
クラウド向けに設計する場合、Springプロファイルを使用するのは望ましい方法ではありません。12ファクターアプリの標準では、環境変数の使用が推奨されています。12factor.net
Mikhail Golubtsov

6
このトピックは少し古いです。ただし、環境変数の設定とスプリングプロファイルの設定の両方を組み合わせることができます。開発プロファイルには静的情報が必要ですが、本番プロファイルでは環境変数を利用できます。このようにして、開発者が開発プロファイルをデプロイするだけの場合、開発者は自分のマシンで環境変数を定義する必要がなくなります。
underscore_05

72

さまざまな環境でさまざまな設定を行う最も簡単な方法は、スプリングプロファイルを使用することです。外部化された構成を参照してください。

これにより、柔軟性が大幅に向上します。私は自分のプロジェクトでそれを使用しており、非常に役に立ちます。あなたの場合、3つのプロファイルがあります:「ローカル」、「ジェンキンス」、および「オープンシフト」

:あなたは、その後3プロファイルの特定のプロパティファイルを持っている application-local.propertiesapplication-jenkins.propertiesと、application-openshift.properties

そこで、関連する環境のプロパティを設定できます。アプリを実行するときは、次のようにアクティブ化するプロファイルを指定する必要があります。 -Dspring.profiles.active=jenkins

編集する

Spring Docによると、システム環境変数SPRING_PROFILES_ACTIVEを設定してプロファイルをアクティブ化でき 、パラメーターとして渡す必要はありません。

実行時にWebアプリのアクティブプロファイルオプションを渡す方法はありますか?

いいえ。Springは、アプリケーションコンテキストを構築するときの最初のステップの1つとしてアクティブプロファイルを決定します。次に、アクティブなプロファイルを使用して、読み取るプロパティファイルとインスタンス化するBeanを決定します。アプリケーションが開始されると、これは変更できません。


4
私はこの答えが好きですが、プロファイル名を環境から取得したい場合はどうなりますか?私は-Dspring.active.profiles = $ SPRING_ACTIVE_PROFILESを試し、/ etc / profile.d / myenvvars.shでOSの環境変数を設定しましたが、Spring Bootはそれをピックアップしません
Tom Hartwell

1
SPRING_PROFILES_ACTIVEがあるため、スプリングブーツの緩和バインディング機能の作品docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/...
feed.me

5
この回答に感謝します。ステファン、私にとってはうまくいきましたが、1つの変更点があります-プロパティは実際にはspring.profiles.activeであり、spring.active.profilesではありません
Rudi

10
Springプロファイルは非常に便利ですが、OPに関しては適切ではありません。これは、ソースコードがどのように保存されるか、およびそれとともに保存されるプロパティ情報の機密性が原因です。OPコンテキストはデータベースアクセスに関連しています。そのような状況では、ソースのプレーンテキストで製品の詳細を必要としません。つまり、ソースが侵害された場合、データベースも侵害されます。代わりに、Vaultなどの環境変数またはシークレットツールを使用することをお勧めします。私は環境を好む。また、一貫性を保つために、すべての環境が同じように動作するようにします。将来の事故を防ぎます。
kipper_t 2017

2
アプリケーションJARの外部にあるSpring Bootプロファイルプロパティファイルを使用できます。たとえば、この環境固有のファイルapplication-production.propertiesは、安全な方法で本番マシンにデプロイされ、通常はアプリケーションのソースコードリポジトリにはありません。
コリンDベネット

13

私の評判は直接コメントするほど高くないので、これは多くのコメントへの応答です。

アプリケーションコンテキストがまだロードされていない限り、実行時にプロファイルを指定できます。

// 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");

12

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}

この問題を解決するために、この環境変数を作成しました。通常は、.envファイルを作成します。

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root

そして変数を私の環境にエクスポートします:

export $(cat .env | xargs)

そして最後にただコマンドを実行します

mvn spring-boot:run

または、jarファイルを実行します

java -jar target/your-file.jar

ここに別のアプローチがあります:https : //docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html


1
env-varsとは何ですか?それらはどのように使用されます。あなたの答えは完全な説明のないものを参照しており、リンクは含まれていません。私はこれにほとんど反対票を投じましたが、あなたの担当者が21であるので、あなたは新しく、一人があなたの答えが役に立ったと思ったので、それを手放しましたが、今後の回答でより多くの情報を提供し、SO(Stack Overflow)へようこそ。楽しんでいただければ幸いです。
PatS

2
@PatSに感謝します。詳細を追加しました。役立つことを願っています。
フェリペジロッティ

1
優れた変更。回答を更新していただきありがとうございます。
PatS

9

以下は、さまざまな環境で読み込まれる一連の環境プロパティファイルを介したスニペットコードです。

アプリケーションリソース(src / main / resources)の下のプロパティファイル:-

 1. application.properties
 2. application-dev.properties
 3. application-uat.properties
 4. application-prod.properties

理想的には、application.propertiesには、すべての環境からアクセス可能なすべての共通プロパティが含まれ、環境関連プロパティは指定された環境でのみ機能します。したがって、これらのプロパティファイルをロードする順序は次のようになります-

 application.properties -> application.{spring.profiles.active}.properties.

ここにコードスニペット:-

    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);

        }
    }

2
Spring Bootはそのままの状態でこのシナリオを処理しませんか?こちらの外部設定ドキュメントを
ChickenFeet

4

これを書くのは遅すぎるかもしれませんが、プロパティを読み取るためのメソッドをオーバーライドしようとしたときに、同様の問題が発生しました。

私の問題は次のとおりです。1)このプロパティがenvに設定されている場合、envからプロパティを読み取ります。2)このプロパティがシステムプロパティに設定されている場合、システムプロパティからプロパティを読み取ります。3)最後に、アプリケーションプロパティから読み取ります。

したがって、この問題を解決するには、Bean構成クラスに移動します

@Validated
@Configuration
@ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX)
@PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class)
@Data // lombok
public class ApplicationConfiguration {

    static final String PREFIX = "application";

    @NotBlank
    private String keysPath;

    @NotBlank
    private String publicKeyName;

    @NotNull
    private Long tokenTimeout;

    private Boolean devMode;

    public void setKeysPath(String keysPath) {
        this.keysPath = StringUtils.cleanPath(keysPath);
    }
}

@PropertySourceのファクトリを上書きします。そして、プロパティを読み取るための独自の実装を作成しました。

    public class PropertySourceFactoryCustom implements PropertySourceFactory {

        @Override
        public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
            return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource);
        }


    }

そしてPropertySourceCustomを作成しました

public class PropertySourceCustom extends ResourcePropertySource {


    public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(EncodedResource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, Resource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(Resource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
        super(name, location, classLoader);
    }

    public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException {
        super(location, classLoader);
    }

    public LifeSourcePropertySource(String name, String location) throws IOException {
        super(name, location);
    }

    public LifeSourcePropertySource(String location) throws IOException {
        super(location);
    }

    @Override
    public Object getProperty(String name) {

        if (StringUtils.isNotBlank(System.getenv(name)))
            return System.getenv(name);

        if (StringUtils.isNotBlank(System.getProperty(name)))
            return System.getProperty(name);

        return super.getProperty(name);
    }
}

だから、これは私を助けました。


4

Springコンテキスト5.0を使用して、次のアノテーションを介して、システム環境に基づいた正しいプロパティファイルのロードに成功しました

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:application-${MYENV:test}.properties")})

ここでMYENV値はシステム環境から読み取られ、システム環境が存在しない場合、デフォルトのテスト環境プロパティファイルがロードされます。誤ったMYENV値を指定すると、アプリケーションの起動に失敗します。

注:各プロファイルについて、維持する必要があります。application-[profile] .propertyファイルを作成する必要があります。Spring ブートではなくSpringコンテキスト5.0を使用しましたが、これはSpring 4.1でも機能すると思います


3

私は質問の著者と同じ問題に直面しました。私たちのケースでは、私のチームのメンバーごとに異なるローカル環境があり.gitignore、異なるdb接続文字列と資格情報を持つファイルを確実に必要とするため、この質問の答えは十分ではなく、人々は共通のファイルをコミットしませんでした誤って他のユーザーのdb接続を切断してください。

それに加えて、以下の手順に従った場合、さまざまな環境に簡単に展開でき、さらにおまけとして、バージョン管理に機密情報を含める必要がまったくありませんでした

parameters.yml(.gitignored)とparameters.yml.dist(これは最初のからを作成するサンプルです)を持つPHP Symfony 3フレームワークからアイデアを得ますcomposer install

以下の回答からの知識を組み合わせて、次のことを行いました:https : //stackoverflow.com/a/35534970/986160https://stackoverflow.com/a/35535138/986160

基本的に、これにより、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

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

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

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

同じことが.propertiesでも行えます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.