web-dev-qa-db-ja.com

Spring Bootのapplication.propertiesでenv変数を使う

私たちはSpring Bootウェブアプリに取り組んでおり、私たちが使っているデータベースはMySqlです。

  • 我々が持っているセットアップは、我々が最初にそれをテストすることですローカルに(私たちのPCにMySqlをインストールする必要があることを意味します)。

  • それからBitbucketにプッシュします。

  • Jenkinsは自動的に新しいPush to 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");

今残された唯一のことは私たちのapplication.propertiesでこれらのJava変数を使う必要があるということです、そしてそれは我々が問題を抱えているものです。

application.propertiesがそれらを参照できるようにするには、passworduserNamesqlURL、およびsqlPortの各変数を割り当て、どのようにそれらをapplication.propertiesに含める必要がありますか。

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

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

これまでのところ運はありません。これらのenv変数を正しいクラス/フォルダーに入れていないか、application.propertiesで間違って使用している可能性があります。

どうぞよろしくお願いします。

ありがとうございます。

117
S M

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 によって提案されている方法がより望ましいです。なぜなら、この場合、ただ1つのenv変数を宣言する必要があるからです:spring.profiles.active。 Springは適切なプロパティファイルをapplication-{profile-name}.propertiesテンプレートによって自動的に読み込みます。

125
Ken Bekov

環境ごとに異なる設定をする最も簡単な方法は、スプリングプロファイルを使用することです。 外部設定 を参照してください。

これはあなたに多くの柔軟性を与えます、私は私のプロジェクトでそれを使っています、そしてそれは非常に役に立ちます。あなたのケースでは、 'local'、 'jenkins'、 'openshift'の3つのプロファイルがあります。

これで、3つのプロファイル固有のプロパティファイルがapplication-local.propertiesapplication-jenkins.propertiesapplication-openshift.propertiesになりました

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

編集する

春のドキュメントによると、プロファイルをアクティブにしてパラメータとして渡さないようにするには、OS環境変数SPRING_PROFILES_ACTIVEを設定するだけです。

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

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

私の評判が直接コメントするのに十分高くないので、これは多くのコメントに対応しています。

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

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

He​​re は、さまざまな環境用にロードされている一連の環境プロパティファイルを通したスニペットコードです。

あなたのアプリケーションリソースの下のプロパティファイル( 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);

        }
    }
4
Ajay

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/example/run-env -variables.html

3
Felipe Girotti

Spring context 5.0を使用して、私は以下のアノテーションを通してシステム環境に基づいて正しいプロパティファイルをロードすることに成功しました

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

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

注:各プロファイルについて、維持したい - application- [profile] .propertyファイルを作成する必要があります。また、私はSpringコンテキスト5.0を使用しましたが、 &Spring bootではありません - 春4.1

2

私は質問の著者と同じ問題に直面しました。私たちの場合、私のチームの各メンバーはそれぞれ異なるローカル環境を持っていたので、この質問の答えは十分ではなく、間違いなく異なるデータベース接続文字列と資格情報を持つファイルを.gitignoreする必要がありました。誤ってファイルを作成し、他のデータベースのDB接続を切断する。

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

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

私は以下の答えからの知識を組み合わせて以下をしました: https://stackoverflow.com/a/35534970/986160https://stackoverflow.com/a/35535138/986160

基本的にこれは spring configurationの継承 を使用し、次のように追加の機密性の高いクレデンシャルを加えた上の設定からアクティブプロファイルを選択する自由を与えます。

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(devサーバー上の.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: local
  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でも同じことができます。

1

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

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

だから、これは私を助けています。

1
Maksym Galich