Spring: Почему мы автоматически подключаем интерфейс, а не реализованный класс?

145

пример

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

Может кто-то объяснить это мне.

  • Как Spring узнает, какой полиморфный тип использовать.
  • Мне нужно @Qualifierили @Resource?
  • Почему мы автоматически подключаем интерфейс, а не реализованный класс?
переполнение стека
источник
11
Вы автоматически подключаете интерфейс, чтобы можно было подключить другую реализацию - это одна из точек кодирования интерфейса, а не класса.
Дэйв Ньютон
Вы бы подключили другую реализацию; Я не понимаю вопроса.
Дэйв Ньютон,
Если мы подключаемся к интерфейсу, что произойдет, если в классе Impl есть метод видимости по умолчанию, к которому мне нужен доступ? Я не могу добавить эту заглушку метода в интерфейс, потому что открытый интерфейс не может содержать модификатор по умолчанию.
jlewkovich
Возможный дубликат класса Spring Autowiring по сравнению с интерфейсом?
OhadR
1
Я считаю, что создание интерфейса только для одной реализации - глупая практика, принятая в мире Java. В результате получается много мусорного кода, но всем приятно, что они следовали правилам SOLID и OOP. Используйте уловку и выбросьте пружину на свалку истории.
avgolubev

Ответы:

229

Как Spring узнает, какой полиморфный тип использовать.

Пока существует только одна реализация интерфейса и эта реализация аннотирована с @Componentвключенным сканированием компонентов Spring, среда Spring может найти пару (интерфейс, реализация). Если сканирование компонентов не включено, вам необходимо явно определить компонент в файле application-config.xml (или эквивалентном файле конфигурации Spring).

Мне нужен @Qualifier или @Resource?

Если у вас есть более одной реализации, вам необходимо квалифицировать каждую из них, и во время автоматического подключения вам нужно будет использовать @Qualifierаннотацию для внедрения правильной реализации вместе с @Autowiredаннотацией. Если вы используете @Resource (семантика J2EE), вы должны указать имя bean-компонента, используя nameатрибут этой аннотации.

Почему мы автоматически подключаем интерфейс, а не реализованный класс?

Во-первых, всегда полезно кодировать интерфейсы в целом. Во-вторых, в случае Spring вы можете внедрить любую реализацию во время выполнения. Типичный вариант использования - внедрить фиктивную реализацию на этапе тестирования.

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

Конфигурация вашего bean-компонента должна выглядеть так:

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

В качестве альтернативы, если вы включили сканирование компонентов в пакете, где они присутствуют, вы должны квалифицировать каждый класс @Componentследующим образом:

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

Затем workerв MyRunnerбудет введен с экземпляром типа B.

Викдор
источник
@stackoverflow Редактировать вопрос не имеет смысла, в ответе должен быть новый код. Иначе вопрос не имеет смысла, потому что ответил бы сам.
Дэйв Ньютон,
Викдор - см. Отредактировать. Это правильный способ аннотировать классы и внедренный объект?
stackoverflow
1
@VictorDombrovsky @Autowired @Qualifier("a1") a;Действителен?
Lucky
1
@ К счастью, я ошибся. Я имел в виду@Autowired @Qualifier("a1") A a;
Виктор Домбровский
1
Вы даже можете использовать @Profile в реализации, чтобы контролировать, какая реализация должна быть внедрена для этого интерфейса через аргументы программы или свойства приложения.
b15