Внедрение зависимостей Java: XML или аннотации

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

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

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

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

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

Есть другие вопросы?

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

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

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

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

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


person Ilya K    schedule 14.02.2011    source источник


Ответы (10)


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

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

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

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

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

Конфигурация XML имеет много недостатков.

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

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

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

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

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

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

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

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

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

person ColinD    schedule 14.02.2011
comment
Единственный недостаток, который я могу понять в аннотациях, - это когда у вас есть библиотека с некоторыми классами, которые МОГУТ использовать DI, аннотации будут перетаскивать зависимость Spring в эту библиотеку. Если вы используете xml в приложении, которое будет использовать библиотеку, только приложение должно будет зависеть от spring. (Предположим, мы говорим о Spring DI, я считаю, что Guice в этом вопросе не исключение). - person Ivaylo Slavov; 08.12.2011

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

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

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

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

person Bozho    schedule 14.02.2011

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

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

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

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

Изменить: вот мнение о @Autowired и XML, с которым я полностью согласен: Использование Spring @Autowired < / а>

person esaj    schedule 14.02.2011

Я предпочитаю, чтобы мой код был ясным, как вы указали. XML лучше, по крайней мере, для меня, в принципе IOC.

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

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

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

person Aito    schedule 14.02.2011
comment
аннотации - это метаданные - они не участвуют в поиске. Единственное отличие - это расположение метаданных. И это не нарушает принципов IoC. - person Bozho; 14.02.2011
comment
Я согласен. Я не хотел иметь в виду, что инъекции нарушают принципы IoC. Я пытался указать на то, что для меня более ясно, что метаданные не попадают в классы. - person Aito; 14.02.2011
comment
Лично я думаю, что это нормально признать реальность того, что вы используете контейнер DI, поскольку вы можете получить реальную выгоду, делая это, и никаких недостатков. - person ColinD; 14.02.2011

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

person Speck    schedule 14.02.2011

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

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

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

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

person Robert Martin    schedule 14.06.2012


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

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

person SebiF    schedule 23.02.2011
comment
Похоже, Guice может читать файлы конфигурации (свойства) прямо из коробки: stackoverflow.com/questions/4805874/ - person mjn; 25.02.2011

Мне просто нужно кое-что добавить к тому, что уже здесь.

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

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

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

person Ryan Nelson    schedule 01.04.2012

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

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

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

person user1889543    schedule 09.12.2012