はじめに
ZYYXのアドベントカレンダー企画で4本目の投稿となります
最近知った、SpringのPostConstrcutが便利と感じたので、備忘録として記します
環境変数を元に初期化をする
ここでは、プロパティファイルから値を読み込んで初期化処理を行うような場合を考えます
例として、AzureのNotificationHubsでプッシュ通知を送信する、RepositoryクラスにてNotificationHubクラスを初期化するケースとします
NotificationHubsのようなサービスは、プロパティファイルにて環境ごとにハブ名や接続文字列を管理をし、利用していると思います
プロパティファイルから値を取得して、@Valueアノテーションによって値の注入を行う場合、以下のようなコードになります
このときのNotificationHubの初期化をどうするのかというのが今回の議題です
notification.connection-string=Endpoint=sb://...
notification.hub-name=my-hub
@Repository
public class NotificationHubRepository {
@Value("${notification.connection-string}")
private String connectionString;
@Value("${notification.hub-name}")
private String hubName;
// こいつをどう初期化するか
private NotificationHub hub;
}
コンストラクタでできないのか?
ここで以下のようにコンストラクタとして初期化する場合を考えてみます
@Repository
public class NotificationHubRepository {
@Value("${notification.connection-string}")
private String connectionString;
@Value("${notification.hub-name}")
private String hubName;
private NotificationHub hub;
public NotificationHubRepository() {
// ❌ @Valueが注入前となるためエラーとなる
this.hub = new Notificationhub(connectionString, hubName);
}
}
なんとなくいけそうな感じがしますが、コンストラクタは値の注入前に実行され、@ValueによるconnectionStringおよびhubNameは未セットとなりエラーになります
PostConstructの利用
ここで登場してくるのが、PostConstructになります
PostConstructは、依存性の注入が完了した後に一度だけ呼び出され、実行されるため@Valueにより値の注入をしているフィールドを利用した初期化であってもエラーが発生しません
ちなみに、PostConstructのinitメソッドはprivateでもpublicでも問題ありません
notification.connection-string=Endpoint=sb://...
notification.hub-name=my-hub
@Repository
public class NotificationHubRepository {
@Value("${notification.connection-string}")
private String connectionString;
@Value("${notification.hub-name}")
private String hubName;
private NotificationHub hub;
@PostConstruct
private void init() {
// @Value 注入後なので安全
this.hubClient = new NotificationHub(connectionString, hubName);
}
public void send(Notification notification) {
hub.sendNotification(notification, "サンプルタグ");
}
}
メリット
⭕️ 環境変数などの値や依存性の注入後に実行できる
⭕️ 一度だけ実行されるため、初期化処理に最適
注意点
❌ 初期化したフィールドを他のクラスで利用できないため再利用性は低い
利用ケース
・@Valueや@Autowiredをしたフィールドを利用して初期化を行う様なケース
・外部サービスとの接続確認などをPostConstrcutにより行うケース
まとめ
PostConstrcut自体はそこまで頻繁に利用できる様なものではないんですが、使えるときに使ってみると便利だな〜という感想です
Springにはまだまだ把握できていないアノテーションやフレームワークの動きがあると思いますが、地道に学習していくことが大事かなと思います