Javaのオープンチャットにて、「SpringBootの起動時にDBアクセスしてマスタデータを保持することは可能ですか?」といった質問が出てきました。
この記事は、解決方法として挙げられたPostConstruct
という処理を理解していなかったので、PostConstruct
を勉強するための記事です。
環境
- Java
- 15
- org.springframework.boot
- 2.4.5
- Lombok
- 1.18.20
※ DIするためにSpringBootを使用していますが、PostConstruct自体はJavaの機能なので、他のフレームワークでも使用できると思います。
ユースケース
- アプリ起動後にDBのデータをキャッシュに持たせたい
- アプリ起動時の設定ファイルの設定をログに出力したい
- DBと設定ファイルが不正な状態の時にアプリ起動を中止させたい
要約
- DI対象としてインスタンスを生成したタイミングで
PostConstruct
を実行する - 単純なインスタンスを作成したタイミングでは実行しない
動作確認
設定ファイルのテスト方法に関しては、こちらの記事を参考にしてください。
プロダクションコード
URLを設定するための抽象クラスExternalProperties
に、Facebookへの設定を読み込ませる具象クラスFacebookProperties
を用意する。
@Getter @Setter @Slf4j @ToString public abstract class ExternalProperties { private String host; private String protocol; private String port; private String endpoint; private String timeout; public URI getUri() { return URI.create(protocol + "://" + host + ":" + port + "/" + endpoint); } @PostConstruct public void display() { log.info("********************"); log.info(this.toString()); log.info("********************"); } @PostConstruct public void validate() { if (host == null) { throw new RuntimeException("設定されていない!"); } } } @Getter @Setter @Configuration @ConfigurationProperties(prefix = "external.facebook") @ToString(callSuper = true) public class FacebookProperties extends ExternalProperties { }
テストコード
テストクラスを用意してPostConstruct
が呼ばれることを確認する。
@SpringJUnitConfig(initializers = ConfigDataApplicationContextInitializer.class) @EnableConfigurationProperties({FacebookProperties.class}) class FacebookPropertiesTests { @Autowired FacebookProperties properties; @Test void AutowiredしないときはPostConstructが呼ばれない() { new FacebookProperties(); // 起動ログを目視で確認する // エラーも発生しない } }
EnableConfigurationProperties
でDI対象としてFacebookProperties
のインスタンスが生成されるタイミングで実行されました。
PostConstruct
という名称から、コンストラクタでのインスタンス生成後に呼ばれるかと思っておりましたが、new FacebookProperties()
したタイミングでは、呼ばれることはありませんでした。
...ログ省略 14:52:22.700 [main] INFO kirimaru.config.ExternalProperties - ******************** 14:52:22.873 [main] INFO kirimaru.config.ExternalProperties - FacebookProperties(super=ExternalProperties(host=localhost, protocol=http, port=10080, endpoint=facebook, timeout=3)) 14:52:22.874 [main] INFO kirimaru.config.ExternalProperties - ******************** ...ログ省略
備考
この機能を知ったうえでも、PostConstruct
を使用せずに、mainメソッドに書く方が分かりやすいのではないかと思っていました。
その件についても、オープンチャットに書いたところ以下の回答を得られました。
- ユースケさんの回答
- Springでインジェクトされるコンポーネントに依存しない処理ならそれでもいいですね。Springに用意してもらうDataSourceを使ったり、コンポーネントのフィールド変数においたりするにはPostConstruct使うのがいいですね
- kisさんの回答
- @PostConstructは必要な初期処理がそれぞれのクラスで書けて、mainで気にする必要が無いところですかねー
ソースコード
ExternalProperties.java github.com
テストコード: github.com
終わりに
職場では既にPostConstructを使っていたのですが、その方が既に現場にいないこともあって、なぜ使用しているかを聞くことができませんでした。
PostConstruct
を使用するとソースコード間の結合度が緩くなりすぎて処理が追えなくなるため、ソースコードの可読性を意識するのであればmain処理に書くべきでは?と思っていたこともあり、勉強していませんでした。
今回の件で、PostConstructを使用するユースケースを勉強することができたので、今後の設計レベルを一段階上げられるように出来そうです。
この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。
類似記事
SpringBootでpropertiesやymlの設定ファイルが読み込めることのテストを書く【Java】 nainaistar.hatenablog.com
【2021】SpringBootでpropertiesやymlの設定ファイルが読み込めることのテストを書く nainaistar.hatenablog.com