Почему Spring не поддерживает прямое внедрение зависимостей полей (за исключением автоматического подключения)? - PullRequest
19 голосов
/ 25 марта 2011

Я заинтересован в непосредственном введении зависимости от поля.Традиционно Spring поддерживает как инжекцию конструктора (предоставляя аргументы конструкторам), так и инжекцию на основе сеттера (вызывая сеттеры при вызове).

Тем не менее, Spring также способен к непосредственному внедрению поля (установка полей-членов объекта безметод установки), что подтверждается аннотированием полей с помощью @Autowired.Автопроводка ограничена только "bean-компонентами", поэтому примитивные значения не могут быть введены (хотя это может быть несколько обойдено путем создания bean-компонентов класса "java.lang.String" - это работает, но имеет обычные предостережения при автопроводке.) В дополнение кТаким образом, Spring поддерживает @Value для прямой установки значений для полей-членов из свойств и т. д.

Тем не менее, Spring не позволяет напрямую устанавливать свойства для полей-членов (без автоматической разводки).

Myвопрос: почему?

Очевидно, что он способен на это, так почему бы и нет?Есть ли какие-либо серьезные негативные побочные эффекты, которые мешают этому?Или возможности как-то ограничены, так что имеет смысл только автоматическое подключение?Нужны ли ему какие-то большие хаки, чем вызов сеттеров?

Обратите внимание, что я не хочу обсуждать относительные достоинства сеттеров и геттеров вообще, только причины, по которым Spring сделал такой выбор.

Ответы [ 3 ]

10 голосов
/ 26 марта 2011

Я думаю, что нашел ответ сам. Я перешел к исходному коду Spring и увидел, как на самом деле реализованы эти функции. Вот что я нашел:

Установка свойств через XML, вероятно, является самой старой частью Spring, и она очень сильно зависит от классов "java.beans" для самоанализа, перечисления свойств и т. Д. И совершенно очевидно, что они вообще не поддерживают самоанализ поля. Поверх этого находится механизм преобразования типов, который определяет, как значение свойства может быть преобразовано в подходящее значение для рассматриваемого свойства. Здесь нет аккуратно разделимых частей.

Весь материал @Autowired и т. Д. Реализован в BeanPostProcessor, который имеет собственную механику сопоставления типов, которая не имеет ничего общего с преобразованием типов. Именно поэтому он только вводит бобы. То же самое в значительной степени относится к @Value, это просто то, что решается на месте и не имеет ничего общего со свойствами.

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

Это не совсем ответ «Почему?», Но я думаю, что это более убедительное объяснение того, почему Spring не добавил непосредственное внедрение зависимости от полей, чем другие объяснения, которые я слышал. Если у них нет чего-то фундаментального против этого (что я сомневаюсь, учитывая, что они хотят разрешить настройку существующих сторонних классов, а не только JavaBeans), то это просто вопрос инженерных усилий, чтобы получить функциональность.

9 голосов
/ 25 марта 2011

Аннотация @Autowired использует отражение, чтобы сделать личные поля доступными (см. этот связанный вопрос ).Я вижу три причины, по которым он не используется в конфигурационных файлах Spring.

  1. Поскольку конфигурация происходит по свойствам компонентов (получателям и установщикам), вы не можете сказать точно - в вероятном случае, что оба существуют- если вы хотите, например, вызвать setValue или установить значение члена.
  2. Это нарушает инкапсуляцию.В вашей конфигурации Spring нет причин знать о закрытых переменных-членах.С аннотацией все в порядке, поскольку она уже есть в исходном коде.
  3. Проблемы безопасности.Более строгий менеджер безопасности может не позволить сделать закрытые поля доступными через отражение.
1 голос
/ 08 августа 2011

Это поддерживает это через аннотацию JSR-250 @Resource (в Spring 3.0 +)

Лично я предпочитаю это внедрению сеттера, и у меня смешанные чувства при рассмотрении инъекции в конструктор. Вот соображения, которые я думал о FWIW:

1) Внедрение в конструктор является хорошим способом самодокументирования ваших зависимостей бина (pro) , но создает много DRY-нарушений: (a) закрытое поле, (b) аргумент конструктора, (c) код конструктора для установки поля из параметра, (d) дополнительный код в конфигурации компонента (либо в классах @Configuration, либо в xml). Это ОЧЕНЬ СУХОЕ нарушение только ради некоторой чистоты инкапсуляции, о которой я даже не беспокоюсь. Это всего лишь нарушение инкапсуляции, но оно создает большую зависимость от некоторого контейнера для инъекций, который учитывает аннотации JSR-250 (см. Далее)

2) Создает зависимость от JSR-250-совместимого контейнера. У меня смешанные чувства по этому поводу. Когда я впервые услышал о @Resource, я написал, что это сделает мою систему более сложной для тестирования. Тем не менее, я все равно использовал в своих тестах пружину. Я все еще могу использовать ложные бобы, как и в любом случае, так что это никогда не было проблемой. И вопрос вне тестирования, когда вы действительно хотите использовать это снова. На мой взгляд, если вы разрабатываете систему, чтобы использовать в своих интересах контейнер, то используйте его и используйте. Действительно ли сухие нарушения стоят гибкости от того, что они не работают внутри контейнера? По крайней мере, с аннотациями JSR-250 вы можете работать в любой среде JEE6 и получать инъекции так, как вы этого хотите.

3) Может создать несколько не очень хороших сценариев отладки, если вы создадите один экземпляр вне контейнера: то есть вы получите исключения с нулевым указателем вместо чего-то приятного. Это компромисс. Я лично думаю, что это не ужасно - я имею в виду, если вы получаете NPE на линии с @Resource, то вы быстро понимаете, что это не было введено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...