spring boot で、@Autowired アノテーションは何がうれしいのか?
都度、new する書き方だと何が不便なのか?がよくわからなかったため、調べたことをメモします。
DIコンテナがどうこう、という難しいことは一旦触れないで、直感的にわかりやすい部分だけ説明します。
@Autowiredを使わない場合と、使う場合を比較
例えば、下記のような依存関係にある 3つのクラス Application, BusinessService, DatabaseService を比較します。ここでいう「依存」とは、クラスの引数に別のクラスのインスタンスをとっている、という意味です。
public class DatabaseService {
public void saveData(String data) {
// データを保存するロジック
}
}
public class BusinessService {
private DatabaseService databaseService;
public BusinessService(DatabaseService databaseService) {
this.databaseService = databaseService;
}
public void processData(String data) {
// データ処理のロジック
databaseService.saveData(data);
}
}
public class Application {
private BusinessService businessService;
public Application() {
// 依存性の手動セットアップ
DatabaseService databaseService = new DatabaseService();
businessService = new BusinessService(databaseService);
}
public void run() {
String data = "Some data";
businessService.processData(data);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DatabaseService {
public void saveData(String data) {
// データを保存するロジック
}
}
@Component
public class BusinessService {
private DatabaseService databaseService;
@Autowired
public BusinessService(DatabaseService databaseService) {
this.databaseService = databaseService;
}
public void processData(String data) {
// データ処理のロジック
databaseService.saveData(data);
}
}
@Component
public class Application {
private BusinessService businessService;
@Autowired
public Application(BusinessService businessService) {
this.businessService = businessService;
}
public void run() {
String data = "Some data";
businessService.processData(data);
}
}
この時点ですでに、@autowiredを使う方がコードが少なくすっきりしていますが、autowiredのメリットはもう一つあります。
ここで、BusinessServiceクラスの引数(= 依存先)インスタンスが、
databaseService から anotherDatabaseService へ変更になったとします。
「@Autowiredを使わない場合」のコードでは、anotherDatabaseServiceのクラスを定義するのに加えて、Applicationクラスの定義も書き換えねばなりません(下記)。
public class Application {
private BusinessService businessService;
public Application() {
// DatabaseService を AnotherDatabaseService に書き換え
AnotherDatabaseService anotherDatabaseService = new AnotherDatabaseService();
businessService = new BusinessService(anotherDatabaseService);
}
public void run() {
String data = "Some data";
businessService.processData(data);
}
}
しかし、「@Autowiredを使った場合」のコードでは、Applicationクラスの定義中に DatabaseService のインスタンスは表れないため、DatabaseServiceとBusinessService間の依存関係が変化しても、わざわざApplicationクラスの定義を書き換えなくてよくなります。
//Applicationクラスの定義は、何も書き換えないでOK
public class Application {
private BusinessService businessService;
@Autowired
public Application(BusinessService businessService) {
this.businessService = businessService;
}
public void run() {
String data = "Some data";
businessService.processData(data);
}
}
DatabaseService に依存しているクラスが増えれば増えるほど、このメンテナンス性の良さが効いてくると考えられます。
最初は DatabaseService をスタブで開発したい(例:StabDatabaseService)時なども、最終的にStabDatabaseService を DatabaseService に切り替えなければなりませんが、@Autowiredを使えば、その時のコードの書き換え箇所が少なくなり、ラクになる、ということだと理解しています。