Инъекция Java-зависимостей: XML или аннотации - PullRequest
35 голосов
/ 14 февраля 2011

Аннотации становятся популярными. Spring-3 их поддерживает. CDI сильно зависит от них (я не могу использовать CDI без аннотаций, верно?)

У меня вопрос почему ?

Я слышал несколько вопросов:

  1. «Это помогает избавиться от XML». Но что плохого в XML? Зависимости являются декларативными по своей природе, и XML очень хорош для объявлений (и очень плох для императивного программирования). С хорошей IDE (как идея) очень легко редактировать и проверять xml, не так ли?

  2. «Во многих случаях для каждого интерфейса существует только одна реализация». Это неправда! Почти все интерфейсы в моей системе имеют фиктивную реализацию для тестов.

Есть еще вопросы?

А теперь мои плюсы для XML:

  1. Вы можете вводить что угодно где угодно (не только код с аннотациями)

  2. Что мне делать, если у меня несколько реализаций одного интерфейса? Использовать квалификаторы? Но это заставляет мой класс знать, какая инъекция ему нужна. Это не хорошо для дизайна.

DI на основе XML проясняет мой код: каждый класс не имеет представления о внедрении, поэтому я могу настроить его и выполнить модульное тестирование любым способом.

Что вы думаете?

Ответы [ 10 ]

25 голосов
/ 14 февраля 2011

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

Я думаю, что проблема в том, чтобы быть слишком догматичным в том, что у классов "нет представления об инъекциях". Не должно быть ссылки на контейнер для инъекций в коде класса. Я абсолютно согласен с этим. Однако мы должны четко уяснить один момент: аннотации не являются кодом . Сами по себе они ничего не меняют в том, как ведет себя класс ... вы все равно можете создать экземпляр класса с аннотациями, как если бы их вообще не было. Таким образом, вы можете полностью прекратить использование контейнера DI и оставить там аннотации, и никаких проблем не возникнет.

Когда вы решаете не предоставлять подсказки метаданных о внедрении в классе (то есть аннотации), вы выбрасываете ценный источник информации о том, какие зависимости требуются этому классу. Вы вынуждены либо повторять эту информацию в другом месте (скажем, в XML), либо полагаться на ненадежную магию, такую ​​как автоматическое подключение, которая может привести к неожиданным проблемам.

Чтобы ответить на некоторые ваши конкретные вопросы:

Помогает избавиться от XML

Многие вещи плохи в конфигурации XML.

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

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

Во многих случаях существует только одна реализация для каждого интерфейса

Часто существует только одна реализация каждого интерфейса для отдельной конфигурации приложения (например, производство). Дело в том, что при запуске приложения вам обычно нужно привязать интерфейс только к одной реализации. Затем он может быть использован во многих других компонентах. С конфигурацией XML вы должны указать каждому компоненту, который использует этот интерфейс, чтобы использовать эту конкретную привязку этого интерфейса (или «bean», если хотите). В конфигурации на основе аннотаций вы просто объявляете привязку один раз , а все остальное позаботится автоматически. Это очень важно и значительно уменьшает объем конфигурации, которую вы должны написать. Это также означает, что когда вы добавляете новую зависимость к компоненту, вам часто вообще не нужно ничего менять в вашей конфигурации!

То, что у вас есть фиктивные реализации какого-то интерфейса, не имеет значения. В модульных тестах вы обычно просто создаете макет и передаете его себе ... это не связано с конфигурацией. Если вы установите полную систему для интеграционных тестов с определенными интерфейсами, используя вместо этого макеты ... это ничего не изменит. Для запуска интеграционного теста системы вы по-прежнему используете только одну реализацию, и вам нужно настроить ее только один раз.

XML: вы можете внедрить что угодно куда угодно

Вы можете легко сделать это в Guice, и я думаю, что вы можете сделать это и в CDI.Таким образом, это не значит, что вам абсолютно запрещено делать это с помощью системы конфигурации на основе аннотаций.Тем не менее, я бы рискнул сказать, что большинство внедренных классов в большинстве приложений - это классы, которые можно добавить к себе @Inject, если его еще нет.Наличие легкой стандартной библиотеки Java для аннотаций (JSR-330) еще больше упрощает для других библиотек и каркасов предоставление компонентов с аннотированным конструктором @Inject в будущем.

Более одной реализацииинтерфейса

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

10 голосов
/ 14 февраля 2011

У меня есть следующий принцип: компоненты, связанные с конфигурацией, определяются с помощью XML. Все остальное - с аннотациями.

Почему? Потому что вы не хотите менять конфигурацию в классах. С другой стороны, гораздо проще написать @Service и @Inject в классе, который вы хотите включить.

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

Что касается CDI - он имеет расширение для конфигурации XML, но вы правы, он использует в основном аннотации. Это то, что мне не особенно нравится в этом.

4 голосов
/ 14 февраля 2011

На мой взгляд, это больше вопрос вкуса.

1) В нашем проекте (с использованием Spring 3) мы хотим, чтобы файлы XML-конфигурации были именно такими: конфигурация. Если его не нужно настраивать (с точки зрения конечного пользователя) или какая-то другая проблема не заставляет его делать это в xml, не помещайте bean-определений / wirings в XML-конфигурации, используйте @Autowired и такие.

2) В Spring вы можете использовать @Qualifier для соответствия определенной реализации интерфейса, если существует несколько. Да, это означает, что вы должны назвать реальные реализации, но я не против.

В нашем случае, использование XML для обработки всего DI сильно раздувает файлы конфигурации XML, хотя это может быть сделано в отдельном xml-файле (или файлах), так что это не , что действительная точка;). Как я уже сказал, это дело вкуса, и я просто думаю, что проще и понятнее обрабатывать инъекции с помощью аннотаций (вы можете увидеть, какие сервисы / репозитории / что бы то ни было, просто взглянув на класс вместо просмотра XML-файла). ищу объявление о бобе).

Редактировать: Вот мнение о @Autowired и XML, с которым я полностью согласен: Spring @Autowired

4 голосов
/ 14 февраля 2011

Мне нравится держать мой код в чистоте, как вы указали.XML лучше, по крайней мере для меня, по принципу МОК.

Фундаментальный принцип внедрения зависимостей для конфигурации заключается в том, что объекты приложения не должны отвечать за поиск ресурсов или сотрудников, от которых они зависят.Вместо этого контейнер IoC должен настраивать объекты, выводя поиск ресурсов из кода приложения в контейнер.(J2EE Development без EJB - Род Джонсон - стр. 131)

Опять же, это просто моя точка зрения, там нет фундаментализма:)

РЕДАКТИРОВАТЬ: Некоторые полезные обсуждения там:

3 голосов
/ 14 февраля 2011

"Но что плохого в XML?"Это еще один файл для управления и еще одно место, где нужно искать ошибку.Если ваши аннотации находятся рядом с вашим кодом, гораздо проще управлять и отлаживать.

2 голосов
/ 14 июня 2012

Как и все вещи, внедрение зависимостей должно использоваться в модерации. Более того, все атрибуты инъекций должны быть отделены от кода приложения и отнесены к коду, связанному с main.

В общем случае приложения должны иметь границу, отделяющую абстрактный код приложения от конкретных деталей реализации. Все зависимости исходного кода, которые пересекают эту границу, должны указывать на приложение. Я называю конкретную сторону этой границы главным разделом, потому что именно там должен жить «главный» (или его эквивалент).

Основной раздел состоит из реализаций фабрики, реализаций стратегии и т. Д. И именно по этой стороне границы структура внедрения зависимостей должна выполнять свою работу. Затем эти внедренные зависимости могут быть переданы через границу в приложение обычными средствами. (например, в качестве аргументов).

Количество вводимых зависимостей должно быть относительно небольшим. Дюжина или меньше. В этом случае решение между XML или аннотациями является спорным.

1 голос
/ 23 февраля 2011

В моем случае разработчики, пишущие приложение, отличаются от тех, кто его настраивает (разные отделы, разные технологии / языки), а последняя группа даже не имеет доступа к исходному коду (что имеет место во многих корпоративных установках).).Это делает Guice непригодным для использования, поскольку мне пришлось бы предоставлять исходный код, а не использовать xmls, настроенные разработчиками, реализующими приложение.

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

1 голос
/ 14 февраля 2011

Также не забудьте Spring JavaConfig .

0 голосов
/ 09 декабря 2012

XML обладает единственным преимуществом декларативного стиля, который определен четко отделенным от самого кода приложения.Это остается независимым от проблем DI.Недостатками являются многословность, плохая надежность повторного факторинга и общее поведение при сбое во время выполнения.Существует только общая (XML) поддержка инструментов с небольшим преимуществом по сравнению с поддержкой IDE, например, для Java.Кроме того, этот XML сопровождается повышением производительности, поэтому обычно он медленнее, чем решения для кода.

Аннотации часто называют более интуитивно понятными и надежными при перефакторинге кода приложения.Также они получают выгоду от лучшего руководства IDE, такого как Guice.Но они смешивают код приложения с проблемами DI.Приложение становится зависимым от платформы.Четкое разделение практически невозможно.Аннотации также ограничены при описании различных действий инъекции в одном и том же месте (конструктор, поле) в зависимости от других обстоятельств (например, проблема ног робота).Более того, они не позволяют обрабатывать внешние классы (код библиотеки) как ваш собственный источник.Поэтому считается, что они работают быстрее, чем XML.

Оба метода имеют серьезные недостатки.Поэтому Я рекомендую использовать Silk DI .Он декларативно определен в коде (отличная поддержка IDE), но на 100% отделен от кода вашего приложения (без фреймворковой зависимости).Это позволяет обрабатывать весь код одинаково, независимо от того, взят ли он из вашего источника или из внешней библиотеки.Такие проблемы, как проблема с ножками робота , легко решаются с помощью обычных привязок.Кроме того, он имеет хорошую поддержку, чтобы адаптировать его к вашим потребностям.

0 голосов
/ 02 апреля 2012

Я просто хочу добавить пару вещей к тому, что уже здесь.

  • Для меня конфигурация DI - это код.Я хотел бы рассматривать это как таковой, но сама природа XML предотвращает это без дополнительных инструментов.

  • Spring JavaConfig - важный шаг вперед в этом отношении, но он все еще имеет сложности.Сканирование компонентов, автоматический выбор реализаций интерфейса и семантика перехвата CGLIB аннотированных классов @Configuration делают его более сложным, чем необходимо.Но это все еще шаг вперед по сравнению с XML.

  • Преимущество отделения метаданных IoC от объектов приложения преувеличено, особенно в Spring.Возможно, если вы ограничитесь только контейнером Spring IoC, это будет правдой.Но Spring предлагает широкий стек приложений, построенный на контейнере IoC (Security, Web MVC и т. Д.).Как только вы используете все это, вы все равно привязываетесь к контейнеру.

...