SpringでInterfaceを@Autowiredするだけで動作するのはなぜ?
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!");が実行されます。