Spring Bootで定義ファイル(yaml)を参照する

2016.03.28

はじめに

タイトル通りSpring Bootでyaml形式の定義ファイルを参照してみたので、その手順について書いていきたいと思います。

手順について

早速手順についてです。今回は何も無い所からSpring Bootのプロジェクトを作成したので、そこから書いていきます。

1.プロジェクトの作成

プロジェクトの雛形を作成するのにSpring Initializrを使用します。必要な項目を入力し「Generate Project」を押下すると、プロジェクトの雛側を作成してくれる画面です。今回は以下のように入力し、プロジェクトを作成しました。

  • 「Gradle Project」を選択
  • Spring Bootのバージョンは1.3.3(デフォルト)
  • Group、Artifactは任意の値
  • Selected Dependenciesは何も選択しない

2.定義ファイル

作成したプロジェクトに定義ファイルを作成します。今回はデフォルトと本番用の2種類の定義ファイルを用意して、参照してみることにします。src/main/resources/configフォルダ内に、以下2つのファイルを用意しました。

application.yml(デフォルト)
settings:
  region: ap-northeast-1
  s3:
    bucket: t-honda-test
    file: "test.txt"
application-production.yml(本番用)
settings:
  region: prod-ap-northeast-1
  s3:
    bucket: prod-t-honda-test
    file: "prod-test.txt"

3.定義ファイルの値を格納するクラス

上記の定義ファイルから値を読み込み、格納するクラスを作成します。「@ConfigurationProperties」アノテーションを付与することで、これを実現できるようです。

Settings.java
package com.sample;

import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "settings")
public class Settings {
    private String region;
    private Map<String, String> s3;
    
    public void setRegion(String region){
        this.region = region;
    }
    
    public String getRegion(){
        return region;
    }
    
    public void setS3(Map<String, String> s3){
        this.s3 = s3;
    }
    
    public Map<String, String> getS3(){
        return s3;
    }
}

定義ファイルで定義した項目をメンバ変数として保持しています。定義ファイル上でネストしていない項目(region)はString型を、ネストしている項目(s3)はMapとして宣言していることに注意してください。宣言したメンバ変数のGetter、Setterを用意することで、定義ファイルの値をこのクラスを通じて参照できるようになります。

4.定義ファイルの値の読み込み

上記の「Settings」クラスを参照し、定義ファイルの値を返却するクラスです。以下の様なソースとなりました。

ConfigReader.java
package com.sample;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ConfigReader {
    @Autowired
    private Settings settings;
    
    public String getRegion(){
        return settings.getRegion();
    }
    
    public String getBucket(){
        Map<String, String> map = settings.getS3();
        return map.get("bucket");
    }
    
    public String getFile(){
        Map<String, String> map = settings.getS3();
        return map.get("file");
    }
}

こちらについても、定義ファイル上でネストして定義した値についてはMapから該当項目を取得していることに注意してください。

main

最後にアプリケーションのエントリーポイントとなるmainです。上記のConfigReaderが返却した定義ファイルの値を、標準出力するようにしました。

SpringBootConfigApplication.java
package com.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootConfigApplication implements CommandLineRunner{
    @Autowired
    private ConfigReader configReader;
    
	public static void main(String[] args) {
		SpringApplication.run(SpringBootConfigApplication.class, args);
	}
	
	@Override
    public void run(String... args) {
        System.out.println("Region = " + configReader.getRegion());
        System.out.println("Bucket = " + configReader.getBucket());
        System.out.println("file = " + configReader.getFile());
    }
}

実行

では、上記の手順で作成したソースをビルドして実行してみたいと思います。gradleで「build」タスクを指定して実行し、jarを作成します。

デフォルトでの起動

作成したjarをデフォルトモードで起動します。以下のように、単純にjarを起動するだけです。

$ java -jar spring-boot-config-0.0.1-SNAPSHOT.jar
  
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.3.RELEASE)

(中略)
Region = ap-northeast-1
Bucket = t-honda-test
file = test.txt
(中略)

application.ymlに定義した値が読み込まれる事が分かるかと思います。

本番モードでの起動

次に本番モードでの起動です。以下のように「--spring.profiles.active=production」をjarの起動オプションに指定します。

$ java -jar spring-boot-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=production

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.3.RELEASE)
(中略)
Region = prod-ap-northeast-1
Bucket = prod-t-honda-test
file = prod-test.txt
(中略)

application-production.ymlに定義した値が読み込まれた事が分かるかと思います。

(余談)lombokを使用したボイラーテンプレートの削除

上記で定義ファイルからの読み込みを行うことはできました。ですがLombokを使用するとSettingsクラスのGetter、Setterを省略することができます。「build.gradle」に「compile('org.projectlombok:lombok:1.16.6')」を追記し、Settingsクラスを以下のように変更します。

Settings.java
package com.sample;

import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import lombok.Data;

@Component
@ConfigurationProperties(prefix = "settings")
@Data
public class Settings {
    private String region;
    private Map<String, String> s3;
}

「@Data」アノテーションを追加することで、Getter、Setterをソース上に明示的に記述する必要が無くなりました。個人的には、こちらの方がスッキリとしていて好みです。

まとめ

以上でSpring Bootで定義ファイルを参照することができました。Spring Bootを使用する際の参考になれば幸いです。

参考サイト

以下のサイトを参考にさせて頂きました。ありがとうございました。
Spring Boot: @ConfigurationProperties を付けたクラスには setter が必要
Spring Boot @ConfigurationProperties
Spring-Bootの設定プロパティと環境変数