したがって、Springを使用していたので、依存関係のあるサービスを記述する場合、次のようにします。
@Component
public class SomeService {
@Autowired private SomeOtherService someOtherService;
}
同じ目標を達成するために別の規則を使用するコードを実行しました
@Component
public class SomeService {
private final SomeOtherService someOtherService;
@Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
これらの方法はどちらも機能します、私はそれを理解しています。しかし、オプションBを使用する利点はありますか?私にとっては、クラスと単体テストでより多くのコードを作成します。 (コンストラクタを記述できず、@ InjectMocksを使用できない)
私が見逃しているものはありますか?単体テストにコードを追加する以外に、自動配線されたコンストラクターは他に何かしますか?これは依存性注入を行うためのより好ましい方法ですか?
はい、実際にはフィールドインジェクションよりもオプションB(コンストラクタインジェクションと呼ばれます)が推奨されており、いくつかの利点があります。
Spring-寄稿者の一人によるより詳細な記事については このブログ投稿 を参照してください Olivier Gierke 。
簡単な言葉で説明します。
Option(A)、では、(Springコンテナの外部/内部の異なるクラスの)だれでも、デフォルトのコンストラクタ(new SomeService()
など)を使用してインスタンスを作成できます。これはSomeOtherService
オブジェクト( SomeService
の依存関係として)。
単体テストにコードを追加する以外に、自動配線されたコンストラクターは他に何かしますか?これは依存性注入を行うためのより好ましい方法ですか?
Option(B)が推奨されるアプローチは、実際にSomeService
依存関係を解決せずにSomeOtherService
オブジェクトを作成できないためです。
Autowired
コンストラクターは、スプリングコンテナーに登録する前にカスタムコードを追加するためのフックを提供します。 SomeService
クラスがSuperSomeService
という名前の別のクラスを拡張し、引数として名前を受け取るコンストラクターがあるとします。この場合、Autowired
コンストラクターは正常に機能します。また、初期化する他のメンバーがある場合は、インスタンスをスプリングコンテナに返す前にコンストラクタでそれを行うことができます。
public class SuperSomeService {
private String name;
public SuperSomeService(String name) {
this.name = name;
}
}
@Component
public class SomeService extends SuperSomeService {
private final SomeOtherService someOtherService;
private Map<String, String> props = null;
@Autowired
public SomeService(SomeOtherService someOtherService){
SuperSomeService("SomeService")
this.someOtherService = someOtherService;
props = loadMap();
}
}
実際、私の経験では、2番目のオプションの方が優れています。 @Autowired
の必要なし。実際、フレームワークと緊密に結合されていないコードを作成する方が賢明です )。 遅延意思決定アプローチを採用するために可能な限り試行するコードが必要です。それは可能な限り pojo であり、フレームワークを簡単に交換できるほどです。したがって、次のように、個別の構成ファイルを作成し、そこにBeanを定義することをお勧めします。
SomeService.Javaファイル内:
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
ServiceConfig.Javaファイル内:
@Config
public class ServiceConfig {
@Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
実際、それについて深く技術的になりたい場合は、サイズに応じて、フィールドインジェクション(@Autowired
)を使用すると生じるスレッドセーフの質問(特に)があります。明らかにプロジェクトの。 これを確認してください自動配線の長所と短所 の詳細をご覧ください。実際、中核の人々は、フィールドインジェクションの代わりにコンストラクタインジェクションを使用することを実際に推奨しています。
知っておくと良い
コンストラクター呼び出しが1つだけの場合、@ Autowiredアノテーションを含める必要はありません。次に、次のようなものを使用できます。
@RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
... Spring Data Repositoryインジェクションの例。