2016-10-06 9 views
30

Я прочитал в некоторых сообщениях о Spring MVC и Portlets, что инъекция в поле не рекомендуется. Потому что я пытаюсь получить. Так что я спросил себя, могу ли я использовать инъекции поля, и я не могу ответить на него. Как я понимаю это инъекции поле если вы впрыснуть Bean в атрибут с @Autowired как это:Что такое полевая инъекция и как ее избежать?

CartController.java:

... 
@Autowired 
private Cart cart; 
... 

BookshopConfiguartion.java:

@Configuration 
public class BookShopConfiguration { 

@Bean 
public Cart cart(){ 
    return new Cart(); 
} 
//more configuration 

My Cart.java предназначен для хранения и предоставления информации о книги в корзине.

В ходе моих исследований я прочитал о инъекции конструктора:

MyComponent.java:

... 
public class MyComponent{ 
private Cart cart; 

@Autowired 
public MyComponent(Cart cart){ 
    this.cart = cart; 
} 
... 

Каковы преимущества и недостатки этих двух типов инъекций?


EDIT 1: Поскольку этот вопрос помечено как дубликат this question я проверил его. Потому что нет никаких примеров кода ни в вопросе, ни в ответах, которые мне не понятны, если я прав с моим предположением, какой тип инъекции я использую.

ответ

70

типы Инъекции

Там находятся три варианта, как зависимости могут быть введены в бобе: 1. С помощью конструктора 2. Через сеттеров или другие методы 3. С помощью отражения непосредственно в полях

Вы используете опцию 3 - это когда вы используете @Autowired непосредственно в своем поле.


принципы Инъекции

общее руководство, as recommended also by Spring (см Конструктор на основе или сеттер на основе DI секция) имеет следующий вид:

  • Для обязательных зависимостей или при прицеливании для неизменности, использование Впрыск конструктора
  • Для опциональных или изменяемых зависимостей используйте установку вставки
  • Избегайте инъекции в большинстве случаев.

поле впрыска Недостатки

Причина, почему инъекции поля неодобрения являются следующими:

  • Вы не можете создавать неизменные объекты, как с воспламенением конструктора
  • Ваших классов герметичная муфта с контейнером DI и не может использоваться за ее пределами
  • Ваши классы не могут быть созданы (например, в модульных тестах) без отражения. Вам нужен контейнер DI для их создания, что больше похоже на интеграционные тесты.
  • Ваши реальные зависимости скрыты снаружи и не отражены в вашем интерфейсе - конструкторы или методы
  • Очень легко иметь 10 зависимостей. Если вы использовали инъекцию конструктора, наличие конструктора с 10 аргументами будет сигнализировать о том, что что-то подозрительное.Но вы можете добавлять введенные поля, используя полевую инъекцию на неопределенный срок. Слишком много зависимостей - это красный флаг, который класс обычно делает больше, чем одно, и это может быть нарушение принципа единой ответственности.

Заключение

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


Дополнительная литература

Я написал статью блога о том, почему, как правило, не рекомендуется инъекции поле - вы можете проверить его здесь - Field Dependency Injection Considered Harmful.

+4

Это вообще нехорошая идея, и нехорошо сказать миру: «инъекции в полете следует избегать». Покажите профи и контрас и позвольте другим самим решать;) У многих людей есть другой опыт и собственный взгляд на вещи. – dit

+4

Это может быть здесь, но есть и другие случаи, когда сообщество приходит к общему мнению, чтобы отговорить что-то. Возьмем, к примеру, венгерскую нотацию. – Jannik

+0

Вы даете несколько хороших моментов в качестве проверяемости и видимости зависимости, но я не согласен со всеми. Инъекция конструктора не имеет недостатков? Желательно иметь 5 или 6 полей для ввода в класс, который выполняет реальные композиции вызова. Я тоже не согласен с вами с неизменностью. Наличие окончательных полей не является обязательным для того, чтобы класс неизменен. Это предпочтительнее. Это совсем другое. – davidxxx

11

Вопрос о вкусе. Это твое решение.

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

  1. Я не хочу, чтобы реализовать конструктор для всех моих @Service, @Repository и @Controller бобов. Я имею в виду, что около 40-50 бобов или больше. Каждый раз, когда я добавляю новое поле, мне придется расширять конструктор. Нет. Я не хочу этого, и мне это не нужно.

  2. Что делать, если вашему компоненту (службе или контроллеру) требуется много других компонентов, которые нужно вводить? Конструктор с 8 параметрами очень уродлив.

  3. Если я использую CDI, конструктор меня не касается.


EDIT: Войтех Ружичка сказал:

класс имеет слишком много зависимостей и, вероятно, нарушает единый принцип ответственности и должен быть переработан

Да. Теория и реальность. Ниже приведен пример: DashboardController, нанесенный на один путь *:8080/dashboard.

My DashboardController собирает много информации из других служб, чтобы отобразить их на странице обзора приборной панели/системы. Мне нужен этот единственный контроллер. Поэтому я должен защищать только этот путь (базовый фильтр авторизации пользователя или пользователя).

+10

Очень уродливый конструктор с 8 зависимостями на самом деле потрясающий, поскольку он является красным флагом, что-то не так, класс имеет слишком много зависимостей и, вероятно, нарушает принцип единой ответственности и должен быть реорганизован. На самом деле это хорошо. –

+1

@VojtechRuzicka это не очень приятно, но иногда вы не можете этого избежать. – dit

+2

Я бы сказал, что эмпирическое правило 3, не говоря уже о 40-50, зависимости для любого класса должно быть признаком того, что вам нужно реорганизовать. Нет никакого способа, чтобы класс с 40 зависимостями придерживался принципа единой ответственности или открытого/закрытого принципала. –

17

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

Конструктор инъекции

Pros:

  • Лучше проверяемость. Вам не нужна какая-либо насмешливая библиотека или контекст Spring в модульных тестах. Вы можете создать объект, который хотите протестировать, с ключевым словом . Такие тесты всегда быстрее, потому что они не полагаются на механизм отражения. (This question было задано через 30 минут. Если бы автор использовал инъекцию конструктора, он бы не появился).
  • Неизменяемость. После установки зависимостей они не могут быть изменены.
  • Безопасный код. После выполнения конструктора ваш объект готов к использованию, так как вы можете проверить все, что было передано в качестве параметра. Объект может быть либо готов, либо нет, между ними нет состояния. При инъекции поля вы вводите промежуточный шаг, когда объект является хрупким.
  • Чистое выражение обязательных зависимостей. Полевая инъекция неоднозначна в этом вопросе.
  • Заставляет разработчиков задуматься о дизайне. dit написал о конструкторе с 8 параметрами, что на самом деле является признаком плохой конструкции и the God object anti-pattern. Не имеет значения, имеет ли класс 8 зависимостей в своем конструкторе или в полях, это всегда неправильно. Люди более неохотно добавляют больше зависимостей к конструктору, чем через поля. Он работает как сигнал к вашему мозгу, что вы должны остановиться на некоторое время и подумать о своей структуре кода.

Минусы:

  • Больше код (но современные Иды облегчить боль).

В принципе, впрыск поля является противоположным.