springboot

こんにちは。
6月も終わりに近づき、夏らしい日が増えてきましたね。
そんな今日は、社内でSpringBootを利用している案件のコード改善内容についてご紹介します。

SpringBoot @Autowired警告について

まずは結論から。
下記が、以前から警告が出ていたコード。

/**
* Autowiredが警告された...
*/
@Autowired
HelloService helloService;

// これを、こう出来ればより良い。

private final HelloService helloService;

// (Spring 4.3からは単一のコンストラクタの場合、@Autowired不要になる)
// @Autowired
public HelloRestController(HelloService helloService) {
this.helloService = helloService;
}

コンストラクタ・インジェクションが推奨される理由

上記のように、コンストラクタ・インジェクションとする事が推奨されている観点には下記のような物があります。
・単一責任の原則
コンストラクタ・インジェクションが多い場合
そのクラスが多くの依存関係を持っている = クラスの責任が大きすぎる
と言えます。
これはSRP(単一責任の原則)に違反している状態であり、あまり良くない状態です。
その点、コンストラクタ・インジェクションを利用すれば
そのクラスがどの程度の依存関係を持っているのか一目瞭然ですね。

・不変性
上記コードにも記載していますが、コンストラクタ・インジェクションを行う場合
フィールドにfinalの修飾子を付与できます。
この事により、その後の処理で内容が変更されたりといった事による事故が起こりづらい
実装とする事ができ、それに起因した不具合の防止にも繋がります。

(補足)循環依存

しかしながら、必ずしもフィールド・インジェクションからコンストラクタ・インジェクションへ
変更すれば全て解決するというわけではありません。
特に循環依存は、例えば
ClassA -> ClassB
ClassB -> ClassC
ClassC -> ClassA
といった依存関係を持っている状態でClassAを利用しようとした際、ClassAが依存しているClassBが依存しているClassCに
ClassAそのものが含まれている(ややこしいですね笑)ため、Exceptionが発生します。

// 例)循環依存の例
// (helloServiceとByeServiceがお互いに依存しているため循環依存となってしまっている)
┌─────┐
| helloService defined in file [/.../service/HelloService.class]
↑     ↓
| byeService defined in file [/.../service/ByeService.class]
└─────┘

このような場合でも、フィールド・インジェクションのままにしておけば動くのですが
そもそも循環依存となっている状態はADP(非循環依存関係の原則)に違反しているため
クラス・メソッドの設計に改善の余地があるという事になります。
このように、小さい事でも一つづつ改善していけば、塵も積もれば・・で保守性の向上が見込めそうですね。

以上、今回はSpringBootで@Autowiredしている場合のコード改善内容についてでした。