Spring: Pourquoi câblons-nous automatiquement l'interface et non la classe implémentée?

142

Exemple

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

Quelqu'un peut m'expliquer cela.

  • Comment le ressort sait-il quel type polymorphe utiliser.
  • Ai-je besoin @Qualifierou @Resource?
  • Pourquoi câblons-nous automatiquement l'interface et non la classe implémentée?
stackoverflow
la source
10
Vous câblez automatiquement l'interface afin de pouvoir câbler une implémentation différente - c'est l'un des points de codage de l'interface, pas de la classe.
Dave Newton
Vous fileriez dans une implémentation différente; Je ne comprends pas la question.
Dave Newton
Si nous câblons dans l'interface, que se passe-t-il lorsqu'il existe une méthode de visibilité par défaut dans la classe Impl à laquelle j'ai besoin d'accéder? Je ne peux pas ajouter ce stub de méthode à l'interface car l'interface publique ne peut pas contenir le modificateur par défaut.
jlewkovich
Possible duplication de la classe Spring Autowiring vs interface?
OhadR
1
Je pense que créer une interface pour une seule implémentation est une pratique stupide qui est acceptée dans le monde Java. Le résultat est beaucoup de code poubelle, mais tout le monde est heureux d'avoir suivi les règles de SOLID et de POO. Utilisez le guide et jetez le ressort dans la poubelle de l'histoire.
avgolubev

Réponses:

224

Comment le ressort sait-il quel type polymorphe utiliser.

Tant qu'il n'y a qu'une seule implémentation de l'interface et que cette implémentation est annotée avec @Componentl'analyse des composants de Spring activée, Spring Framework peut trouver la paire (interface, implémentation). Si l'analyse des composants n'est pas activée, vous devez définir le bean explicitement dans votre application-config.xml (ou fichier de configuration Spring équivalent).

Ai-je besoin de @Qualifier ou @Resource?

Une fois que vous avez plusieurs implémentations, vous devez qualifier chacune d'elles et pendant le câblage automatique, vous devrez utiliser l' @Qualifierannotation pour injecter la bonne implémentation, avec l' @Autowiredannotation. Si vous utilisez @Resource (sémantique J2EE), vous devez spécifier le nom du bean à l'aide de l' nameattribut de cette annotation.

Pourquoi câblons-nous automatiquement l'interface et non la classe implémentée?

Premièrement, il est toujours recommandé de coder sur des interfaces en général. Deuxièmement, en cas de printemps, vous pouvez injecter n'importe quelle implémentation au moment de l'exécution. Un cas d'utilisation typique consiste à injecter une implémentation fictive pendant la phase de test.

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

Votre configuration de bean devrait ressembler à ceci:

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

Sinon, si vous avez activé l'analyse des composants sur le package où ils sont présents, vous devez qualifier chaque classe @Componentcomme suit:

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

Ensuite, workerin MyRunnersera injecté avec une instance de type B.

Vikdor
la source
@stackoverflow Modifier la question n'aurait aucun sens, un nouveau code fait partie de la réponse. Sinon, la question n'a aucun sens, car elle aurait répondu d'elle-même.
Dave Newton
Vikdor - veuillez voir modifier. Est-ce la bonne façon d'annoter les classes et l'objet injecté?
stackoverflow
1
@VictorDombrovsky Est-ce @Autowired @Qualifier("a1") a;valide?
Chanceux du
1
@Lucky j'ai fait une erreur. Je voulais dire@Autowired @Qualifier("a1") A a;
Victor Dombrovsky
1
Vous pouvez même utiliser @Profile sur l'implémentation pour contrôler quelle implémentation doit être injectée pour cette interface via des arguments de programme ou des propriétés d'application.
b15