本日も実務の実装の中で、学んだことがあったので備忘録として書き残しておこうと思います。
このドキュメントについて
ymlファイル(外部ファイル)からデータを読み込む以下2つのやり方についてです。
- @Valueを利用した読み込み方法
- @ConfigurationPropertiesを利用した読み込み方法
実行環境
・Java17
・SpringBoot 3.0.2
build.gradleの設定は以下
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.2'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-mail'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
実装
applivation.ymlファイルには以下設定しておきます。(メール送信に使ってた)
spring:
mail:
host: smtp.gmail.com
port: 587
username: dummy
password: dummy
1. @Valueを利用した読み込み方法
ymlファイルの値を単体で取得したい場合には、@Valueで良いと思う。
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Getter
public class MailConfigValue {
@Value("${spring.mail.port}")
private int port;
}
説明:
-
値を設定したいフィールドに@Valueを付与して、引数に設定したいymlファイルの値の変数名を階層ごとに.でつないで記載する。
-
@Componentは、アプリケーション起動時にこのクラスをDIコンテナに登録してくれるので、依存性注入を行うことでportの値を取り出せるようになる。
-
取り出しには@Getterを付与しているので、getPort()でオッケー。
下記が例。
@Service
@RequiredArgsConstructor
@Slf4j
public class MailSenderService {
private final MailConfigValue mailConfigValue;
public void smtpMailSender() {
log.info(String.valueOf(mailConfigValue.getPort()));
return true;
}
}
2. @ConfigurationPropertiesを利用した読み込み方法
値を複数まとめて取得したい場合には、@ConfigurationPropertiesを利用する。
package com.example.demo.config;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
@RequiredArgsConstructor
@Getter
@ConfigurationProperties(prefix="spring.mail")
public class MailConfig {
private final String host;
private final int port;
private final String userName;
private final String password;
}
説明:
-
データを設定するクラスを用意し、ymlファイルの変数と同じ名前の変数名を定義する。
-
@ConfigurationPropertiesを付与し、prefixに設定したい値がある階層まで記載する。
-
注意したいのが、@ConfigurationPropertiesはsetterがないと、データを設定できないので、アプリケーションが起動しない。
→@RequiredArgsConstructorを付与して、コンストラクタで値を設定できるようにしてあげるか、lombokの@Data等付与してあげる必要がある。 -
@ConfigurationPropertiesは、@ConfigurationPropertiesScanを起動クラスに記載する必要がある。
これがないと、@ConfigurationPropertiesを読みにいかないので、アプリケーションが起動しない。 -
@ConfigurationPropertiesScanは、DIコンテナに登録も行ってくれるので、依存性注入を行うことでymlファイルの値が利用できるようになる。
下記のように、起動クラスに@ConfigurationPropertiesScanを設定する。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@ConfigurationPropertiesScan
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
まとめ
@Valueを利用するシーンはあんまりないかもしれない。
複数つけるような場面であれば、@ConfigurationPropertiesを利用すると思うし。。
setterが必要とかも知らずに、なんとなく既存コードを真似して書いていたので、よくないなと思いました。
しっかり、1つずつの意味を理解しながら実装するべきですね、、