Spring @Autowire много бобов - PullRequest
       21

Spring @Autowire много бобов

0 голосов
/ 03 марта 2020

Я пишу класс Factory, который в зависимости от заданного параметра будет возвращать различные реализации интерфейса:

class Factory {
 public MyType getType(String param) {
  if (param.equals("A")) {
     return new MyTypeA();
   } else if (param.equals("B")) {
     return new MyTypeB();
 } 
}

Теперь вместо new я хочу использовать возможности Spring для внедрения зависимостей. Я хочу использовать автоматическую разводку на основе @Annotation.

Первое, что приходит на ум, это использовать @Autowire в поле примерно так:

class Factory {
@Autowired
private MyTypeA myTypeA;
@Autowired
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

Но потом я вспоминаю, что автоматическая разводка полей не рекомендуется потому что это трудно для модульного тестирования таких классов.

Следующее, что я мог бы попробовать, - это использовать автоматическую разводку на уровне сеттера, чтобы разрешить тестирование:

class Factory {
private MyTypeA myTypeA;
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 

@Autowired
public void setMyTypeA(MyTypeA a) {
 this.myTypeA = a;
}

@Autowired
public void setMyTypeB(MyTypeB b) {
 this.myTypeB = b;
}
}

Хорошо, это выглядит лучше, но подождите, Более того, я хочу, чтобы мой класс был неизменным, поэтому я хочу, чтобы мои личные поля были окончательными и заполнялись только во время конструктора. Следующее, что я мог бы попробовать, это инжекция на основе конструктора:

class Factory {

private final MyTypeA myTypeA;
private final MyTypeB myTypeB;

public Factory(MyTypeA myTypeA, MyTypeB myTypeB) {
 this.myTypeA = myTypeA;
 this.myTypeB = myTypeB;
}

         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

выглядит хорошо, но возникает вопрос - если у меня есть 20 различных типов, я могу вернуться с этой фабрики в зависимости от значения параметра, я могу Не создавайте конструктор из 20 параметров.

Пожалуйста, предложите, какой подход был бы наилучшим в этом случае (пытаясь избежать автопроводки на основе xml).

Спасибо

Ответы [ 2 ]

1 голос
/ 03 марта 2020

Предполагая, что все ваши MyType классы уже являются bean-компонентами, управляемыми Spring, вы можете просто использовать список.

Предполагая,

@Configuration
class Config{
   @Bean
   public MyType myTypeA() {
      return new MyTypeA();
   }
   @Bean
   public MyType myTypeB() {
      return new MyTypeB();
   }
}

Затем вы можете просто передать список в Factory :

@Bean
public Factory factory(List<MyType> myTypes) {
   return new Factory(myTypes);
}

Этот список будет содержать myTypeA и myTypeB. Оттуда, что я, вероятно, сделаю, будет что-то вроде этого в Factory:

public class Factory {

  final Map<String, MyType> myTypes;

  public Factory(List<MyType> types) {
     //build map of types with "param" as the key
  }

  public MyType getType(String param) {
     return myTypes.get(param);
  } 
}
0 голосов
/ 03 марта 2020

Вы можете продолжать следовать этому подходу.

    class Factory {
@Autowired
private MyTypeA myTypeA;
@Autowired
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

Теперь, чтобы решить проблему внедрения макетов в ваших тестовых примерах, вы можете просто использовать аннотацию @InjectMocks, чтобы сделать это.

...