Подтвердить что ты не робот

Почему Spring поддерживает непосредственную инъекцию зависимостей в поле (за исключением автоподключения)?

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

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

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

Мой вопрос: почему?

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

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

4b9b3361

Ответ 1

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

  • Поскольку конфигурация происходит с помощью свойств bean (getters и seters), вы не можете сказать - в вероятном случае, что оба существуют - если вы хотите, например, вызовите setValue или установите значение члена.
  • Это разрушает инкапсуляцию. У вашей конфигурации Spring нет причин знать о частных переменных-членах. С аннотацией, которая хорошо, так как она уже находится прямо в исходном коде.
  • Проблемы безопасности. Более ограничительный менеджер безопасности может не разрешать доступ к закрытым полям через отражение.

Ответ 2

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

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

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

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

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

Ответ 3

Он поддерживает это посредством аннотации JSR-250 @Resource (в Spring 3.0 +)

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

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

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

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