Primavera: Por que ligamos automaticamente a interface e não a classe implementada?

142

Exemplo

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

Alguém pode me explicar isso.

  • Como a primavera sabe qual tipo polimórfico usar.
  • Eu preciso @Qualifierou@Resource ?
  • Por que conectamos automaticamente a interface e não a classe implementada?
stackoverflow
fonte
10
Você conecta automaticamente a interface para poder conectar em uma implementação diferente - esse é um dos pontos de codificação para a interface, não para a classe.
Dave Newton
Você conectaria uma implementação diferente; Eu não entendo a pergunta.
Dave Newton
Se estivermos conectando a interface, o que acontece quando há um método de visibilidade padrão na classe Impl à qual preciso acessar? Não consigo adicionar esse stub de método à interface porque a interface pública não pode conter modificador padrão.
jlewkovich
Possível duplicata da classe Spring Autowiring vs. interface?
OhadR
1
Eu acho que fazer uma interface para apenas uma implementação é uma prática estúpida que é aceita no mundo java. O resultado é muito código de lixo, mas todos estão felizes por terem seguido as regras do SOLID e do OOP. Use o truque e jogue a primavera na lata de lixo da história.
Avgolubev 21/12/19

Respostas:

224

Como a primavera sabe qual tipo polimórfico usar.

Desde que haja apenas uma única implementação da interface e essa implementação seja anotada com @Componenta verificação de componente do Spring ativada, a estrutura do Spring pode descobrir o par (interface, implementação). Se a varredura de componentes não estiver ativada, você deverá definir explicitamente o bean no seu application-config.xml (ou arquivo de configuração equivalente da primavera).

Preciso de @Qualifier ou @Resource?

Depois de ter mais de uma implementação, você precisará qualificar cada uma delas e, durante a fiação automática, você precisará usar a @Qualifieranotação para injetar a implementação correta, juntamente com a @Autowiredanotação. Se você estiver usando @Resource (semântica J2EE), deverá especificar o nome do bean usando o nameatributo desta anotação.

Por que conectamos automaticamente a interface e não a classe implementada?

Em primeiro lugar, é sempre uma boa prática codificar para interfaces em geral. Em segundo lugar, no caso da primavera, você pode injetar qualquer implementação em tempo de execução. Um caso de uso típico é injetar implementação simulada durante o estágio de teste.

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

Sua configuração de bean deve ficar assim:

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

Como alternativa, se você ativou a varredura de componentes no pacote em que estes estão presentes, você deve qualificar cada classe da @Componentseguinte maneira:

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

Em seguida, workerem MyRunnervai ser injectado com uma instância do tipo B.

Vikdor
fonte
@stackoverflow A edição da pergunta não faria sentido, o novo código pertence à resposta. Caso contrário, a pergunta não faz sentido, porque teria respondido a si mesma.
Dave Newton
Vikdor - por favor, veja editar. Essa é a maneira correta de anotar as classes e o objeto injetado?
stackoverflow
1
@VictorDombrovsky É @Autowired @Qualifier("a1") a;válido?
Lucky
1
@ Sorte que cometi um erro. Eu quis dizer@Autowired @Qualifier("a1") A a;
Victor Dombrovsky
1
Você pode até usar o @Profile na implementação para controlar qual implementação deve ser injetada para essa interface por meio de argumentos do programa ou propriedades do aplicativo.
b15