Spring: ¿Por qué conectamos automáticamente la interfaz y no la clase implementada?

142

Ejemplo

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

¿Alguien puede explicarme esto?

  • ¿Cómo sabe la primavera qué tipo polimórfico usar?
  • ¿Necesito @Qualifiero @Resource?
  • ¿Por qué conectamos automáticamente la interfaz y no la clase implementada?
desbordamiento de pila
fuente
10
Automáticamente conecta la interfaz para poder conectar una implementación diferente , ese es uno de los puntos de codificación a la interfaz, no a la clase.
Dave Newton
Conectarías una implementación diferente; No entiendo la pregunta.
Dave Newton
Si estamos cableando en la interfaz, ¿qué sucede cuando hay un método de visibilidad predeterminado dentro de la clase Impl al que necesito acceso? No puedo agregar ese código auxiliar de método a la interfaz porque la interfaz pública no puede contener un modificador predeterminado.
jlewkovich
¿Posible duplicado de la clase Spring Autowiring vs. interfaz?
OhadR
1
Creo que hacer una interfaz para una sola implementación es una práctica estúpida que se acepta en el mundo de Java. El resultado es una gran cantidad de código basura, pero todos están contentos de haber seguido las reglas de SOLID y OOP. Usa el disfraz y tira la primavera al basurero de la historia.
avgolubev

Respuestas:

224

¿Cómo sabe la primavera qué tipo polimórfico usar?

Siempre y cuando solo haya una implementación única de la interfaz y esa implementación esté anotada con @Componentel escaneo de componentes de Spring habilitado, Spring Framework puede encontrar el par (interfaz, implementación). Si la exploración de componentes no está habilitada, debe definir el bean explícitamente en su application-config.xml (o un archivo de configuración de resorte equivalente).

¿Necesito @Qualifier o @Resource?

Una vez que tenga más de una implementación, deberá calificar cada una de ellas y, durante el cableado automático, deberá usar la @Qualifieranotación para inyectar la implementación correcta, junto con la @Autowiredanotación. Si está utilizando @Resource (semántica J2EE), debe especificar el nombre del bean utilizando el nameatributo de esta anotación.

¿Por qué conectamos automáticamente la interfaz y no la clase implementada?

En primer lugar, siempre es una buena práctica codificar interfaces en general. En segundo lugar, en caso de primavera, puede inyectar cualquier implementación en tiempo de ejecución. Un caso de uso típico es inyectar una implementación simulada durante la etapa de prueba.

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

Su configuración de bean debería verse así:

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

Alternativamente, si habilitó la exploración de componentes en el paquete donde están presentes, entonces debe calificar cada clase de la @Componentsiguiente manera:

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

Entonces workeren MyRunnerserá inyectado con una instancia del tipo B.

Vikdor
fuente
@stackoverflow Editar la pregunta no tendría ningún sentido, el nuevo código pertenece a la respuesta. De lo contrario, la pregunta no tiene sentido, porque se habría respondido a sí misma.
Dave Newton
Vikdor: ver edición. ¿Es esa la forma correcta de anotar las clases y el objeto inyectado?
stackoverflow
1
@VictorDombrovsky ¿Es @Autowired @Qualifier("a1") a;válido?
Lucky
1
@Lucky, cometí un error. Quise decir@Autowired @Qualifier("a1") A a;
Victor Dombrovsky
1
Incluso puede usar @Profile en la implementación para controlar qué implementación se debe inyectar para esa interfaz a través de argumentos del programa o propiedades de la aplicación.
b15