Spring: Dlaczego autowireujemy interfejs, a nie zaimplementowaną klasę?

142

Przykład

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();
}

Czy ktoś może mi to wyjaśnić.

  • Skąd wiosna wie, jakiego typu polimorficznego użyć.
  • Czy potrzebuję @Qualifierczy @Resource?
  • Dlaczego autowireujemy interfejs, a nie zaimplementowaną klasę?
przepełnienie stosu
źródło
10
Interfejs jest automatycznie okablowany, więc można podłączyć go do innej implementacji - to jeden z punktów kodowania interfejsu, a nie klasy.
Dave Newton
Możesz połączyć się z inną implementacją; Nie rozumiem pytania.
Dave Newton
Jeśli okablujemy interfejs, co się stanie, gdy w klasie Impl istnieje domyślna metoda widoczności, do której potrzebuję dostępu? Nie mogę dodać tej metody do interfejsu, ponieważ interfejs publiczny nie może zawierać domyślnego modyfikatora.
jlewkovich
1
Myślę, że tworzenie interfejsu tylko dla jednej implementacji jest głupią praktyką akceptowaną w świecie Java. Rezultatem jest dużo śmieciowego kodu, ale wszyscy są zadowoleni, że przestrzegali zasad SOLID i OOP. Skorzystaj ze szczotki i wrzuć sprężynę do śmietnika historii.
avgolubev

Odpowiedzi:

224

Skąd wiosna wie, jakiego typu polimorficznego użyć.

Dopóki istnieje tylko jedna implementacja interfejsu i ta implementacja jest opatrzona adnotacją z @Componentwłączonym skanowaniem komponentów Springa, Spring Framework może znaleźć parę (interfejs, implementacja). Jeśli skanowanie komponentów nie jest włączone, musisz jawnie zdefiniować komponent bean w pliku application-config.xml (lub w równoważnym pliku konfiguracyjnym sprężyny).

Czy potrzebuję @Qualifier lub @Resource?

Gdy masz więcej niż jedną implementację, musisz zakwalifikować każdą z nich, a podczas automatycznego okablowania musisz użyć @Qualifieradnotacji, aby wstrzyknąć właściwą implementację wraz z @Autowiredadnotacją. Jeśli używasz @Resource (semantyka J2EE), powinieneś określić nazwę ziarna, używając nameatrybutu tej adnotacji.

Dlaczego autowireujemy interfejs, a nie zaimplementowaną klasę?

Po pierwsze, ogólnie rzecz biorąc, dobrą praktyką jest kodowanie interfejsów. Po drugie, w przypadku wiosny możesz wstrzyknąć dowolną implementację w czasie wykonywania. Typowym przypadkiem użycia jest wstrzyknięcie fałszywej implementacji na etapie testowania.

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();
}

Twoja konfiguracja fasoli powinna wyglądać następująco:

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

Alternatywnie, jeśli włączyłeś skanowanie komponentów w pakiecie, w którym są one obecne, powinieneś zakwalifikować każdą klasę @Componentw następujący sposób:

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();
}

Następnie workerw MyRunnerbędą wstrzyknięto przykład typu B.

Vikdor
źródło
@stackoverflow Edycja pytania nie miałaby sensu, nowy kod należy do odpowiedzi. W przeciwnym razie pytanie nie ma sensu, ponieważ samo odpowiedziałoby.
Dave Newton,
Vikdor - zobacz edycję. Czy to właściwy sposób na adnotowanie klas i wstrzykniętego obiektu?
stackoverflow
1
@VictorDombrovsky Jest @Autowired @Qualifier("a1") a;ważne?
Lucky
1
@Lucky, popełniłem błąd. Miałem na myśli@Autowired @Qualifier("a1") A a;
Victor Dombrovsky,
1
Możesz nawet użyć @Profile w implementacji, aby kontrolować, która implementacja powinna zostać wstrzyknięta dla tego interfejsu za pośrednictwem argumentów programu lub właściwości aplikacji.
b15