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

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

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

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

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

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

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

Любые другие проблемы?

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

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

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

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

Как вы думаете?

4b9b3361

Ответ 1

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

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

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

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

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

Многие вещи плохо связаны с конфигурацией XML.

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

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

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

существует только одна реализация,

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

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

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

EDIT: Некоторые полезные обсуждения:

Ответ 4

По-моему, это скорее вопрос вкуса.

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

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

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

Изменить: вот мнение о @Autowired vs. XML, с которым я полностью согласен: Spring @Автоматическое использование

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

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

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

Ответ 10

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

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

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