Spring: Warum verdrahten wir die Schnittstelle automatisch und nicht die implementierte Klasse?

142

Beispiel

interface IA
{
  public void someFunction();
}

@Resource(name="b")
class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}

@Resource(name="c")
class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

class MyRunner
{

  @Autowire
  @Qualifier("b") 
  IA worker;

  worker.someFunction();
}

Kann mir das jemand erklären.

  • Woher weiß Spring, welcher polymorphe Typ verwendet werden soll?
  • Benötige ich @Qualifieroder @Resource?
  • Warum verdrahten wir die Schnittstelle automatisch und nicht die implementierte Klasse?
Paketüberfluss
quelle
10
Sie verdrahten die Schnittstelle automatisch, damit Sie eine andere Implementierung verkabeln können - dies ist einer der Codierungspunkte für die Schnittstelle, nicht für die Klasse.
Dave Newton
Sie würden eine andere Implementierung einbinden. Ich verstehe die Frage nicht.
Dave Newton
Wenn wir die Schnittstelle verkabeln, was passiert, wenn es innerhalb der Impl-Klasse eine Standardsichtbarkeitsmethode gibt, auf die ich Zugriff haben muss? Ich kann diesen Methodenstub nicht zur Schnittstelle hinzufügen, da die öffentliche Schnittstelle keinen Standardmodifikator enthalten kann.
Jlewkovich
Mögliches Duplikat der Spring Autowiring-Klasse vs. Schnittstelle?
OhadR
1
Ich denke, eine Schnittstelle für nur eine Implementierung zu erstellen, ist eine dumme Praxis, die in der Java-Welt akzeptiert wird. Das Ergebnis ist viel Müllcode, aber alle sind froh, dass sie die Regeln von SOLID und OOP befolgt haben. Verwenden Sie die Guice und werfen Sie die Quelle in den Mülleimer der Geschichte.
Avgolubev

Antworten:

224

Woher weiß Spring, welcher polymorphe Typ verwendet werden soll?

Solange es nur eine einzige Implementierung der Schnittstelle gibt und diese Implementierung mit @Componentaktiviertem Spring-Komponentenscan kommentiert ist , kann das Spring-Framework das Paar (Schnittstelle, Implementierung) ermitteln. Wenn der Komponentenscan nicht aktiviert ist, müssen Sie die Bean explizit in Ihrer application-config.xml (oder einer entsprechenden Spring-Konfigurationsdatei) definieren.

Benötige ich @Qualifier oder @Resource?

Sobald Sie mehr als eine Implementierung haben, müssen Sie jede davon qualifizieren. Während der automatischen Verkabelung müssen Sie die @QualifierAnnotation verwenden, um die richtige Implementierung zusammen mit der @AutowiredAnnotation einzufügen. Wenn Sie @Resource (J2EE-Semantik) verwenden, sollten Sie den Bean-Namen mithilfe des nameAttributs dieser Anmerkung angeben .

Warum verdrahten wir die Schnittstelle automatisch und nicht die implementierte Klasse?

Erstens ist es immer eine gute Praxis, auf Schnittstellen im Allgemeinen zu codieren. Zweitens können Sie im Falle eines Frühlings jede Implementierung zur Laufzeit einfügen. Ein typischer Anwendungsfall ist das Einfügen einer Scheinimplementierung während der Testphase.

interface IA
{
  public void someFunction();
}


class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}


class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

class MyRunner
{
     @Autowire
     @Qualifier("b") 
     IA worker;

     ....
     worker.someFunction();
}

Ihre Bean-Konfiguration sollte folgendermaßen aussehen:

<bean id="b" class="B" />
<bean id="c" class="C" />
<bean id="runner" class="MyRunner" />

Wenn Sie alternativ den Komponentenscan für das Paket aktiviert haben, in dem diese vorhanden sind, sollten Sie jede Klasse @Componentwie folgt qualifizieren:

interface IA
{
  public void someFunction();
}

@Component(value="b")
class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}


@Component(value="c")
class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

@Component    
class MyRunner
{
     @Autowire
     @Qualifier("b") 
     IA worker;

     ....
     worker.someFunction();
}

Dann workerin MyRunnermit einer Instanz des Typs injiziert werden B.

Vikdor
quelle
@stackoverflow Das Bearbeiten der Frage macht keinen Sinn, neuer Code gehört in die Antwort. Ansonsten macht die Frage keinen Sinn, weil sie sich selbst beantwortet hätte.
Dave Newton
Vikdor - siehe bearbeiten. Ist das der richtige Weg, um die Klassen und das injizierte Objekt zu kommentieren?
Stackoverflow
1
@ VictorDombrovsky Ist @Autowired @Qualifier("a1") a;gültig?
Glücklicher
1
@Lucky Ich habe einen Fehler gemacht. Ich meinte@Autowired @Qualifier("a1") A a;
Victor Dombrovsky
1
Sie können sogar @Profile für die Implementierung verwenden, um über Programmargumente oder Anwendungseigenschaften zu steuern, welche Implementierung für diese Schnittstelle eingefügt werden soll.
b15