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!");が実行されます。