LoginSignup
26
15

More than 3 years have passed since last update.

kotlin × Spring Bootでapplication.ymlから設定値を取得する

Last updated at Posted at 2019-07-21

application.ymlから値を取得する方法は主に以下の3つのやり方があるようです。

  • @Valueアノテーション
  • Environmentクラス
  • @ConfigurationPropertiesアノテーション

それぞれの方法をkotlinで試してみます。

環境

  • JDK: 1.8
  • kotlin: 1.3
  • Spring Boot 2.1.4.RELEASE

以下のapplication.ymlから値を取得します。

application.yml
app-conf:
  numeric-param: 10
  string-param: hogehoge
  structure-param:
    param1: hoge
    param2: fuga

Value

@Valueアノテーションを使用すると簡単に値を取得できます。

ValueComponent.kt
@Component
class ValueComponent {

    @Value("\${app-conf.numeric-param}")
    val numericParam = 0

    @Value("\${app-conf.string-param}")
    val stringParam = ""

    @Value("\${app-conf.undefined-param:defaultValue}")
    val undefinedParam = ""

    @Value("\${app-conf.structure-param.param1}")
    val structureParam1 = ""

    @Value("\${app-conf.structure-param.param2}")
    val structureParam2 = ""

    fun main() {
        println("numericParam=$numericParam")
        println("stringParam=$stringParam")
        println("undefinedParam=$undefinedParam")
        println("structureParam.param1=$structureParam1")
        println("structureParam.param2=$structureParam2")
    }
}
実行結果
numericParam=10
stringParam=hogehoge
undefinedParam=defaultValue
structureParam.param1=hoge
structureParam.param2=fuga

@Valueに渡す文字列は\${}のようにエスケープする必要があります。
またvalで定義した変数であっても値をセットしてくれますが、変数定義時にセットしている値は無視されます。
デフォルト値を設定したい場合は\${変数名:デフォルト値}のようにします。

Environment

取得するパラメータを動的に変更したい場合はEnvironment.getProperty()が使えます。

EnvironmentComponent.kt
@Component
class EnvironmentComponent {

    @Autowired
    lateinit var environment: Environment

    fun main() {
        val numericParam = environment.getProperty("app-conf.numeric-param", Int::class.java, 0)
        val stringParam = environment.getProperty("app-conf.string-param", String::class.java, "")
        val undefinedParam = environment.getProperty("app-conf.undefined-param", String::class.java, "defaultValue")
        val structureParam1 = environment.getProperty("app-conf.structure-param.param1", String::class.java, "")
        val structureParam2 = environment.getProperty("app-conf.structure-param.param2", String::class.java, "")

        println("numericParam=$numericParam")
        println("stringParam=$stringParam")
        println("undefinedParam=$undefinedParam")
        println("structureParam.param1=$structureParam1")
        println("structureParam.param2=$structureParam2")
    }
}
実行結果
numericParam=10
stringParam=hogehoge
undefinedParam=defaultValue
structureParam.param1=hoge
structureParam.param2=fuga

getProperty()の第一引数にキー、第二引数に取得する型のClass、第三引数にデフォルト値を渡します。
なおgetProperty()メソッドはデフォルト値を省略した場合は戻り値がnullableになり、キーが未定義の場合nullが帰ります。
未定義の場合にエラーを発生させたいときはgetProperty()の代わりにgetRequiredProperty()を使用します。

// 未定義の場合エラーになる
val undefinedParam = environment.getRequiredProperty("app-conf.undefined-param", String::class.java)

ConfigurationProperties

@ConfigurationPropertiesアノテーションを使用すると複数のパラメータをまとめて取得することができます。

ConfigurationPropertiesComponent.kt
@Component
class ConfigurationPropertiesComponent {

    @Autowired
    lateinit var appConfig: AppConfig

    fun main() {
        println("numericParam=${appConfig.numericParam}")
        println("stringParam=${appConfig.stringParam}")
        println("undefinedParam=${appConfig.undefinedParam}")
        println("structureParam.param1=${appConfig.structureParam.param1}")
        println("structureParam.param2=${appConfig.structureParam.param2}")
    }
}

@Configuration
@ConfigurationProperties("app-conf")
class AppConfig {

    var numericParam = 0

    var stringParam = ""

    var undefinedParam = "defaultValue"

    val structureParam = StructureParam()
}

class StructureParam {
    var param1 = ""
    var param2 = ""
}
実行結果
numericParam=10
stringParam=hogehoge
undefinedParam=defaultValue
structureParam.param1=hoge
structureParam.param2=fuga

パラメータを受け取るクラスに@ConfigurationPropertiesアノテーションを付与します。
フィールドへはsetter経由で値が設定されるためvalは使用できません。(階層化されたプロパティを除く)
appConfig.structureParam.param1appConfig.structureParam.param2のように階層構造をもったパラメータも取得できます。
ただし、パラメータを受け取るためのインスタンスは自動生成してくれないので、あらかじめインスタンスを生成しておく必要があります。(こちらはvalで定義できます)
また、パラメータ名とフィールド名は厳密に同じでなくてもある程度までいい感じに認識してくれます。

追記

Spring Boot 2.2系から@ConstructorBindingが追加されたため、@ConfigurationPropertiesでdata classが利用可能になりました。
参考 : Spring Boot 2.2系で@ConfigurationPropertiesを使う


@SpringBootApplication
// メインクラスに@ConfigurationPropertiesScanをつける必要があります
@ConfigurationPropertiesScan
class DemoApplication

// ...mainメソッド略...

@Component
class ConfigurationPropertiesComponent {

    @Autowired
    lateinit var appConfig: DataClassConfig

    fun main() {
        println(appConfig)
    }
}

// @ConfigurationPropertiesに@ConstructorBindingを追加
@ConstructorBinding
@ConfigurationProperties("app-conf")
data class DataClassConfig(
    val numericParam: Int,
    val stringParam: String,
    val undefinedParam: String = "defaultValue",
    // 階層構造を持つパラメータも事前のインスタンス化は不要です
    val structureParam: DataClassStructureParam
)

data class DataClassStructureParam(
    val param1: String,
    val param2: String
)

実行結果
DataClassConfig(numericParam=10, stringParam=hogehoge, undefinedParam=defaultValue, structureParam=DataClassStructureParam(param1=hoge, param2=fuga))

まとめ

application.ymlから値を取得する3つの方法をkotlinで試してみました。
それぞれ一長一短あるので適切に使い分けて利用したいです。

参考

50.5 @ConfigurationProperties
Spring Bootの外部設定値の扱い方を理解する

26
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
15