Как установить параметры @Autowired конструктора как "required = false" отдельно

Я использую @Autowired аннотацию в @Configuration класса @Configuration.

@Configuration
public class MyConfiguration {

   private MyServiceA myServiceA;
   private MyServiceB myServiceB

   @Autowired
   public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB){
     this.myServiceA = myServiceA;
     this.myServiceB = myServiceB;    
   }
}

Как документация Spring документации, я могу объявить, требуется ли аннотированная зависимость.

Если я @Autowired аннотацию под конструктором по мере required=false, я говорю, что две службы, которые должны быть автоподписаны, не требуются (как документация Spring документации):

@Autowired(required = false)
public MyConfiguration(MyServiceA myServiceA, MyServiceB myServiceB){
  this.myServiceA = myServiceA;
  this.myServiceB = myServiceB;   
}

Из весенней документации:

В случае нескольких методов аргументов параметр "обязательный" применим для всех аргументов.

Как я могу установить required атрибут для каждого параметра конструктора по отдельности? Необходимо использовать @Autowired аннотацию под каждым полем?

С Уважением,

Ответ 1

Если вы используете Java 8 и Spring Framework 4, вы можете использовать Optional.

@Autowired
public MyConfiguration(Optional<MyServiceA> myServiceA, Optional<MyServiceB> myServiceB){
  myServiceA.ifPresent(service->{this.myServiceA = service});
  myServiceB.ifPresent(service->{this.myServiceB = service});   
}

Ответ 2

Явный подход

В принципе, у вас есть компонент, который имеет некоторые необходимые и необязательные зависимости. Рекомендуемым способом обработки этого сценария, а не только компонентов конфигурации, но любого другого, является создание конструктора только для обязательных зависимостей и использование инъекции установщика для необязательных.

public class MyConfiguration {

   private final MyServiceA myServiceA;
   private MyServiceB myServiceB

   @Autowired
   public MyConfiguration(MyServiceA myServiceA){
     this.myServiceA = myServiceA;   
   }

   @Autowired(required = false)
   public void setMyServiceB(MyServiceB myServiceB) {
     this.myServiceB = myServiceB;
   }

}

При таком подходе вы можете легко тестировать класс без необходимости для какой-либо насмешливой библиотеки. Вы можете создать объект в состоянии тестирования, используя конструктор и дополнительные сеттеры.

Помещение @Autowired(required = false) непосредственно в поле и удаление setter также будет работать, но поскольку вы используете инъекцию конструктора, я предполагаю, что вы хотите явно @Autowired(required = false) зависимости.

Дополнительная идея

Вы также можете рассмотреть использование необязательного типа для обертывания необязательных зависимостей. Обычно разработчики полагают, что если класс обладает свойством, он должен быть установлен, что явно не соответствует вашему сценарию. Чтобы отметить возможность отсутствия для определенных зависимостей более четко, вы, вероятно, можете использовать опцию:

public class MyConfiguration {

   private final MyServiceA myServiceA;
   private Optional<MyServiceB> myServiceB

   @Autowired
   public MyConfiguration(MyServiceA myServiceA){
     this.myServiceA = myServiceA;
     this.myServiceB = Optional.empty();   
   }

   @Autowired(required = false)
   public void setMyServiceB(MyServiceB myServiceB) {
     this.myServiceB = Optional.ofNullable(myServiceB);
   }

}

Некоторые люди не используют тип " Optional " для свойств класса (главным образом, из-за этого ответа от Брайана Гетца), но в конце дня это должно быть решение всей команды, которая будет работать над проектом.

Ответ 3

С весны 4.3.0.RC1 вы можете сделать это:

public MyConfiguration(MyServiceA myServiceA, @Autowired(required = false) MyServiceB myServiceB){
  this.myServiceA = myServiceA;
  this.myServiceB = myServiceB;   
}

Как ElementType.PARAMETER был добавлен как цель аннотации.

В Spring 5.0 @Autowired(required = false) также можно заменить на @Nullable или можно использовать тип @Nullable Kotlin без каких-либо аннотаций, например, MyServiceB?

Ответ 4

Начиная с Spring Framework 5.0, вы также можете использовать аннотацию @Nullable (любого типа в любом пакете, например, javax.annotation.Nullable из JSR-305):

@Configuration
public class MyConfiguration {

   private MyServiceA myServiceA;
   private MyServiceB myServiceB

   @Autowired
   public MyConfiguration(@Nullable MyServiceA myServiceA, MyServiceB myServiceB){
     this.myServiceA = myServiceA;
     this.myServiceB = myServiceB;    
   }
}