JavaとC#は似て非なるものだと日に日に感じる今日この頃です。
悩んだこと
Springでは@Autowired
を使うことで、インスタンス管理をDIコンテナ側に任せることができ、クラス同士を疎結合に保つことができるようになっています。
ある時、私が見たコードでは@Autowired
がクラスではなくインターフェースに付けられていました。
例として挙げると以下のようなコードです。
public interface FugaInterface { public void hello(); }
@Service public class FugaClass implements FugaInterface { @Override public void hello() { System.out.println("hello!"); } }
public class HogeClass { @Autowired private FugaInterface fuga; public void hello() { fuga.hello(); } }
悩んだのは、何故fuga.hello()
が実装クラスであるFugaClass
クラスのメソッドと紐づけられるのか、ということでした。
あくまで@Autowired
されているのはFugaInterface
インターフェースであって、実装クラスではないじゃないか!と思っていました。
結論
Springではインターフェースを
@Autowired
した場合、そのインターフェースを実装したクラスを自動的に探して@Autowired
してくれるもし同じインターフェースを実装したクラスが複数ある場合は、実行時にエラーが発生する
- 明示的に実装クラスの指定が必要になる
なるほど、そんな仕様があったとは…🤔
実装するクラスを指定する場合
同じインターフェースを実装するクラスが複数ある場合は、@Service
のvalue
にIDを指定し、@Autowired
する際に一緒に@Qualifier
を付与します。@Qualifier
には参照したい実装クラスのIDを指定します。
public interface FugaInterface { public void hello(); }
@Service(value="fuga") public class FugaClass implements FugaInterface { @Override public void hello() { System.out.println("hello!"); } } @Service(value="piyo") public class PiyoClass implements FugaInterface { @Override public void hello() { System.out.println("fuck you!"); } }
public class HogeClass { @Autowired @Qualifier("fuga") private FugaInterface fuga; public void hello() { fuga.hello(); } }
上記のコードでは、fuga.hello();
を呼ぶとSystem.out.println("hello!");
が実行されます。