Поддержка beans (@ManagedBean) или CDI Beans (@Named)?

109

Я только что начал читать Core JavaServer Faces, 3-е изд. и они говорят это (выделено мной):

Исторически сложилось так, что существует два отдельных механизма, компоненты CDI и управляемые компоненты JSF, для компонентов, которые могут использоваться на страницах JSF. Мы предлагаем вам использовать компоненты CDI, если ваше приложение не должно работать с обычным исполнителем сервлетов, таким как Tomcat.

Зачем? Они не дают никаких оправданий. Я использовал @ManagedBeanвсе bean-компоненты в прототипе приложения, работающем на GlassFish 3, и на самом деле не заметил никаких проблем с этим. Я не особо возражаю против перехода с @ManagedBeanна @Named, но хочу знать, зачем мне это беспокоить .

Мэтт Болл
источник
4
@Bozho: этот вопрос очень похож, но, прочитав несколько раз ответ Паскаля, я все еще не понимаю, почему CDI намного лучше. Я не знаю CDI, и я счастлив изучить его, так как он «лучше». Почему лучше?
Мэтт Болл,
«если ваше приложение не должно работать на простом средстве выполнения сервлетов, таком как Tomcat» Я использую только tomcat и настоятельно рекомендую CDI. Tomcat может прекрасно это поддерживать
Карл Килден
1
@ KarlKildén «простой исполнитель сервлетов» относится к контейнеру сервлетов, не поддерживающему CDI. На момент написания Tomcat не поддерживал CDI, за исключением небольшого количества магии.
Торбьёрн Равн Андерсен

Ответы:

64

CDI предпочтительнее простого JSF, потому что CDI позволяет внедрять зависимости в масштабе JavaEE. Вы также можете внедрить POJO и позволить им управлять. С JSF вы можете внедрить только часть того, что вы можете с CDI.

Bozho
источник
Итак, в принципе, я могу внедрить экземпляр почти любого класса (при условии, что у него есть «правильный материал» - что это такое, просто конструктор без аргументов? ) С помощью CDI, в то время как я должен использовать, @ManagedBeanесли я хочу ввести его с помощью простого JSF?
Мэтт Болл,
3
@MattBall Мэтт, спустя годы, не могли бы вы прокомментировать этот переход?
Корай Тугай
5
@KorayTugay Я не трогал этот код с июня 2011 года, но я переключился на CDI, и все работало нормально. Я буду рад ответить на любые конкретные вопросы, насколько мне известно, если они у вас есть.
Мэтт Болл
170

Используйте CDI.

Согласно JSF 2.3, @ManagedBeanне рекомендуется . См. Также выпуск спецификации 1417 . Это означает , что есть больше не причина , чтобы выбрать @ManagedBeanболее @Named. Впервые это было реализовано в бета-версии Mojarra 2.3.0 m06.

введите описание изображения здесь


История

Основное отличие в том, что @ManagedBeanон управляется платформой JSF и @ManagedPropertyдоступен только через другие управляемые компоненты JSF. @Namedуправляются сервер приложений (контейнер) через рамки CDI и с помощью @Injectдоступны для любого вида контейнера управляемого артефакта , как @WebListener, @WebFilter, @WebServlet, @Path, @Stateless, и т.д. , и даже JSF @ManagedBean. С другой стороны , на, @ManagedPropertyэто не работает в @Namedили любом другом контейнер управляемого артефакта. Работает реально только внутри@ManagedBean .

Другое отличие состоит в том, что CDI фактически внедряет прокси, делегирующие текущему экземпляру в целевой области для каждого запроса / потока (например, как внедряются EJB). Этот механизм позволяет внедрить компонент с более узкой областью видимости в компонент с более широкой областью видимости, что невозможно с JSF @ManagedProperty. JSF «вводит» сюда физический экземпляр напрямую, вызывая сеттер (именно поэтому сеттер требуется, в то время как это не требуется с@Inject ).

Хотя это и не является прямым недостатком - есть и другие способы - объем @ManagedBeanпросто ограничен. С другой стороны, если вы не хотите раскрывать «слишком много» для @Inject, вы также можете просто сохранить свои управляемые компоненты @ManagedBean. Это как protectedпротив public. Но это не в счет.

По крайней мере, в JSF 2.0 / 2.1 основным недостатком управления компонентами поддержки JSF с помощью CDI является отсутствие эквивалента CDI для @ViewScoped. Примерно @ConversationScopedподходит, но по-прежнему требует запуска и остановки вручную, и добавляет уродливый cidпараметр запроса к URL-адресам результатов. MyFaces CODI упрощает задачу, полностью прозрачно связывая JSF javax.faces.bean.ViewScopedс CDI, так что вы можете просто сделать это @Named @ViewScoped, однако это добавляет некрасивый windowIdпараметр запроса к URL-адресам результатов, также при простой навигации между страницами. OmniFaces решает все это с помощью истинного CDI, @ViewScopedкоторый действительно связывает область действия bean-компонента с состоянием представления JSF, а не с произвольным параметром запроса.

JSF 2.2 (выпущенный через 3 года после этого вопроса / ответа) предлагает новую полностью совместимую с CDI @ViewScopedаннотацию в формате javax.faces.view.ViewScoped. JSF 2.2 даже поставляется с CDI-only, у @FlowScopedкоторого нет @ManagedBeanэквивалента, тем самым подталкивая пользователей JSF к CDI. Ожидается, что @ManagedBeanв соответствии с Java EE 8 и друзья будут устаревшими. Если вы в настоящее время все еще используете @ManagedBean, настоятельно рекомендуется перейти на CDI, чтобы быть готовым к будущим обновлениям. CDI легко доступен в контейнерах, совместимых с Java EE Web Profile, таких как WildFly, TomEE и GlassFish. Для Tomcat вам необходимо установить его отдельно, как и для JSF. См. Также Как установить CDI в Tomcat?

BalusC
источник
4
Я создал beans.xml, преобразовал @ManagedBeanбобы поддержки в формат @Namedи преобразовал @ManagedPropertyв него @Inject. С миром все хорошо. Однако, если я изменю свои @EJBаннотации на @Inject, развертывание завершится неудачно ( org.jboss.weld.exceptions.DeploymentException) с сообщением WELD-001408 Injection point has unsatisfied dependencies. Должен ли я действительно использовать @Injectдля внедрения EJB без интерфейса в @Namedbean-компонент, или я должен придерживаться этого @EJB? EJB упакованы в EJB JAR в том же EAR, что и WAR, который содержит мои bean-компоненты CDI.
Мэтт Болл,
Это должно просто работать. Вы все еще сталкиваетесь с этой проблемой в текущей версии Weld?
BalusC
Увы, не могу сказать. Этот вопрос был задан 2 работодателями более 2 лет назад. Судя по моему старому комментарию к ответу Божо, я, должно быть, перешел на CDI / @Named.
Мэтт Болл
«MyFaces CODI упрощает эту задачу, полностью прозрачно соединяя JSF javax.faces.bean.ViewScoped с CDI, так что вы можете просто сделать это @Named @ViewScoped, однако это добавляет уродливый параметр запроса windowId к URL-адресам результатов, а также при простой навигации между страницами». Обратите внимание, что с DeltaSpike это больше не выполняется. Вы можете отключить параметры URL-адреса dsId и windowId, если вам не нужна область действия окна.
JanM
1
@Jan: А пока у OmniFaces есть JSF 2.2-подобный @ViewScopedдля JSF 2.0 / 2.1: showcase.omnifaces.org/cdi/ViewScoped
BalusC
16

С Java EE 6 и CDI у вас есть разные варианты для управляемых компонентов.

  • @javax.faces.bean.ManagedBeanотносится к JSR 314 и был представлен в JSF 2.0. Основная цель заключалась в том, чтобы избежать конфигурации в файле faces-config.xml для использования компонента внутри страницы JSF.
  • @javax.annotation.ManagedBean(“myBean”) определен в JSR 316. Он обобщает управляемые компоненты JSF для использования в других местах в Java EE.
  • @javax.inject.Named(“myBean”) почти такие же, как и предыдущий, за исключением того, что вам нужен файл beans.xml в папке web / WEB-INF для активации CDI.
h2mch
источник
1
В чем разница между первыми двумя?
Мэтт Болл,
Целью первой аннотации было / было заменить конфигурацию bean-компонента в файле faces-config.xml для использования в JSF. Второй копирует концепт в «контейнер java ee 6». Он имеет больше функций (например, аннотации @PostConstruct и @PreDestroy), но также доступен на странице JSF (с языком выражений).
h2mch
1
зачем тебе нужен beans.xml файл? Так ли это и сегодня?
Туфир,
2
Нет, с JavaEE7 вам больше не нужен beans.xml. см. docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch
1
С JavaEE7 вам не нужен beans.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm (правильная ссылка) blogs.oracle.com/theaquarium/entry/… ( включение CDI по умолчанию в Java EE 7)
М. Атиф Риаз
2

Я использовал CDI в GlassFish 3.0.1, но чтобы заставить его работать, мне пришлось импортировать фреймворк Seam 3 (Weld). Это сработало очень хорошо.

В GlassFish 3.1 перестал работать CDI, и с ним перестал работать Seam Weld. Я обнаружил ошибку по этому поводу, но еще не видел ее исправленной. Мне пришлось преобразовать весь свой код для использования аннотаций javax.faces. *, Но я планирую вернуться к CDI, как только они заработают.

Я согласен, что вам следует использовать CDI, но одна проблема, которую я еще не видел решенной, - это то, что делать с аннотацией @ViewScoped. У меня много кода, который от этого зависит. Неясно, работает ли @ViewScoped, если вы не используете с ним @ManagedBean. Если кто-нибудь может прояснить это, я был бы признателен.

AlanObject
источник
-1

Одна веская причина для перехода на CDI: у вас может быть общий ресурс в области сеанса (например, профиль пользователя) @Inject , включенный как в управляемые компоненты JSF, так и в службы REST (например, Jersey / JAX-RS).

С другой стороны, @ViewScopedэто веская причина придерживаться JSF @ManagedBean- особенно для всего, что требует значительного AJAX. Стандартной замены этого в CDI нет.

Кажется, что он может иметь некоторую поддержку @ViewScopedаннотации a -like для компонентов CDI, но я лично с этим не играл.

http://seamframework.org/Seam3/FacesModule

wrschneider
источник