Fasola (@ManagedBean) czy fasola CDI (@Named)?

109

Właśnie zacząłem czytać Core JavaServer Faces, 3rd Ed. i mówią tak (moje podkreślenie):

To historyczny przypadek, że istnieją dwa oddzielne mechanizmy, fasola CDI i fasola zarządzana przez JSF, dla komponentów bean, które mogą być używane na stronach JSF. Sugerujemy użycie fasoli CDI, chyba że aplikacja musi działać na zwykłym programie uruchamiającym serwlet, takim jak Tomcat.

Czemu? Nie podają żadnego uzasadnienia. Używałem @ManagedBeanwszystkich fasoli w prototypowej aplikacji działającej na GlassFish 3 i tak naprawdę nie zauważyłem żadnych problemów z tym. Nie mam nic przeciwko migracji z @ManagedBeando @Named, ale chcę wiedzieć, dlaczego powinienem się tym przejmować .

Matt Ball
źródło
4
@Bozho: to pytanie jest dość podobne, ale po kilkukrotnym przeczytaniu odpowiedzi Pascala nadal nie rozumiem, dlaczego CDI jest znacznie lepsze. Nie znam CDI i cieszę się, że się go uczę, ponieważ jest „lepszy”. Dlaczego to jest lepsze?
Matt Ball,
„chyba, że ​​aplikacja musi działać na zwykłym programie uruchamiającym serwlet, takim jak Tomcat”. Używam tylko tomcat i zdecydowanie polecam CDI. Tomcat może to dobrze wesprzeć
Karl Kildén
1
@ KarlKildén „zwykły program uruchamiający serwlet” odnosi się do kontenera serwletów nieobsługującego CDI. W chwili pisania tego tekstu Tomcat nie obsługiwał CDI, z wyjątkiem sporej ilości magii.
Thorbjørn Ravn Andersen

Odpowiedzi:

64

CDI jest preferowane w stosunku do zwykłego JSF, ponieważ CDI umożliwia wstrzykiwanie zależności w całym JavaEE. Możesz także wstrzyknąć POJO i pozwolić im zarządzać. Dzięki JSF możesz wstrzyknąć tylko podzbiór tego, co możesz za pomocą CDI.

Bozho
źródło
Więc w zasadzie mogę wstrzyknąć instancję prawie każdej klasy (pod warunkiem, że ma "odpowiednie rzeczy" - co to jest, tylko konstruktor bez argonu? ) Za pomocą CDI, podczas gdy muszę użyć, @ManagedBeanjeśli chcę wstrzyknąć go zwykłym JSF?
Matt Ball
3
@MattBall Matt po latach, czy możesz skomentować tę migrację?
Koray Tugay
5
@KorayTugay Nie dotykałem tego kodu od czerwca 2011, ale przeszedłem na CDI i wszystko działało dobrze. Z przyjemnością odpowiem na wszelkie konkretne pytania najlepiej z mojej pamięci, jeśli je masz.
Matt Ball
170

Użyj CDI.

Zgodnie z JSF 2.3 @ManagedBeanjest przestarzałe . Zobacz także wydanie specyfikacji 1417 . Oznacza to, że nie jest już powodem do wyboru @ManagedBeanponad @Named. Zostało to po raz pierwszy wdrożone w Mojarra 2.3.0 w wersji beta m06.

wprowadź opis obrazu tutaj


Historia

Podstawowa różnica polega na tym, że @ManagedBeanjest zarządzana przez framework JSF i jest @ManagedPropertydostępna tylko dla innego zarządzanego komponentu bean JSF. @Namedjest zarządzany przez serwer aplikacji (kontener) poprzez CDI ram i jest poprzez @Injectdostępny na każdym rodzaju pojemnika zarządzanej artefaktu jak @WebListener, @WebFilter, @WebServlet, @Path, @Stateless, etc a nawet JSF @ManagedBean. Z drugiej strony w sprawie, @ManagedPropertyczy nie działa Wewnątrz @Namedlub innego pojemnika zarządzanej artefaktu. Działa naprawdę tylko wewnątrz @ManagedBean.

Inną różnicą jest to, że CDI faktycznie wstrzykuje serwery proxy delegujące do bieżącej instancji w zakresie docelowym na podstawie żądania / wątku (tak jak w przypadku wstrzykiwania EJB). Mechanizm ten pozwala na wstrzyknięcie ziarna o węższym zakresie do ziarna o szerszym zakresie, co nie jest możliwe w przypadku JSF @ManagedProperty. JSF „wstrzykuje” tutaj fizyczną instancję bezpośrednio, wywołując metodę ustawiającą (dokładnie dlatego jest ona wymagana, podczas gdy nie jest to wymagane w przypadku @Inject).

Chociaż nie jest to bezpośrednio wada - są inne sposoby - zakres @ManagedBeanjest po prostu ograniczony. Z drugiej strony, jeśli nie chcesz narażać się na zbyt wiele @Inject, możesz po prostu zatrzymać zarządzaną fasolę @ManagedBean. To jak w protectedporównaniu public. Ale to się nie liczy.

Przynajmniej w JSF 2.0 / 2.1 główną wadą zarządzania komponentami typu bean obsługującymi JSF przez CDI jest brak odpowiednika formatu CDI @ViewScoped. @ConversationScopedZbliża, ale nadal wymaga ręcznego uruchamiania i zatrzymywania i dołącza brzydki cidparametr zapytania do adresów URL wyniku. MyFaces CODI ułatwia to poprzez w pełni przezroczyste mostkowanie JSF javax.faces.bean.ViewScopeddo CDI, więc możesz to zrobić @Named @ViewScoped, jednak dołącza to brzydki windowIdparametr żądania do URL-i wynikowych wyników, również w zwykłej nawigacji między stronami. OmniFaces rozwiązuje to wszystko za pomocą prawdziwego CDI, @ViewScopedktóry naprawdę wiąże zakres beana ze stanem widoku JSF zamiast z dowolnym parametrem żądania.

JSF 2.2 (który został wydany 3 lata po tym pytaniu / odpowiedzi) oferuje nową, w pełni kompatybilną z CDI @ViewScopedadnotację w wersji javax.faces.view.ViewScoped. JSF 2.2 jest nawet dostarczany z tylko CDI, @FlowScopedktóry nie ma @ManagedBeanodpowiednika, popychając tym samym użytkowników JSF w kierunku CDI. Oczekuje się, że @ManagedBeani znajomi zostaną wycofani zgodnie z Java EE 8. Jeśli nadal używasz @ManagedBean, zdecydowanie zalecamy przejście na CDI, aby przygotować się na przyszłe ścieżki aktualizacji. CDI jest łatwo dostępny w kontenerach zgodnych z Java EE Web Profile, takich jak WildFly, TomEE i GlassFish. W przypadku Tomcata musisz zainstalować go osobno, dokładnie tak, jak to zrobiłeś dla JSF. Zobacz także Jak zainstalować CDI w Tomcat?

BalusC
źródło
4
Utworzyłem beans.xml, przekonwertowałem @ManagedBeanfasolki podkładowe na @Namedi przekonwertowałem @ManagedPropertyna @Inject. Ze światem wszystko jest w porządku. Jeśli jednak zmienię @EJBadnotacje na @Inject, wdrożenie kończy się niepowodzeniem ( org.jboss.weld.exceptions.DeploymentException) z komunikatem WELD-001408 Injection point has unsatisfied dependencies. Czy powinienem używać @Injectdo wstrzykiwania EJB bez interfejsu do @Namedfasoli, czy powinienem się trzymać @EJB? EJB są pakowane w JAR EJB, w tym samym EAR co WAR, który zawiera moje ziarna CDI.
Matt Ball
Powinno po prostu działać. Czy nadal masz ten problem z obecną wersją Weld?
BalusC,
Niestety, nie mogłem powiedzieć. To pytanie jest od 2 pracodawców i> 2 lata temu. Opierając się na moim starym komentarzu do odpowiedzi Bozho, musiałem przejść na CDI / @Named.
Matt Ball
„MyFaces CODI ułatwia to, w pełni transparentnie łącząc javax.faces.bean.ViewScoped JSF z CDI, więc możesz po prostu to zrobić @Named @ViewScoped, jednak dodaje to brzydki parametr żądania windowId do adresów URL wyników, również w zwykłej, waniliowej nawigacji między stronami”. Zauważ, że w przypadku DeltaSpike nie jest to już prawdą. Możesz wyłączyć parametry adresu URL dsId i windowId, jeśli nie potrzebujesz zakresu okna.
Styczeń
1
@Jan: W międzyczasie OmniFaces ma również podobny @ViewScopeddo JSF 2.2 format JSF 2.0 / 2.1: showcase.omnifaces.org/cdi/ViewScoped
BalusC
16

W Javie EE 6 i CDI masz inną opcję dla Managed Beans

  • @javax.faces.bean.ManagedBeanodnosi się do JSR 314 i został wprowadzony w JSF 2.0. Głównym celem było uniknięcie konfiguracji w pliku faces-config.xml w celu użycia ziarna na stronie JSF.
  • @javax.annotation.ManagedBean(“myBean”) jest zdefiniowany przez JSR 316. Uogólnia on komponenty bean zarządzane przez JSF do użytku w innych miejscach w Java EE
  • @javax.inject.Named(“myBean”) są prawie takie same, jak powyżej, z wyjątkiem tego, że do aktywacji CDI potrzebny jest plik beans.xml w folderze web / WEB-INF.
h2mch
źródło
1
Jaka jest różnica między pierwszymi dwoma?
Matt Ball
Celem pierwszej adnotacji jest / było zastąpienie konfiguracji bean w pliku faces-config.xml do użycia w JSF. Drugi kopiuje koncepcję do „kontenera java ee 6”. Ma więcej funkcji (takich jak adnotacje @PostConstruct i @PreDestroy), ale jest również osiągalny przez stronę JSF (z językiem wyrażeń).
h2mch
1
dlaczego potrzebujesz beans.xmlpliku? Czy nadal jest to prawda?
Thufir
2
Nie, z JavaEE7 nie potrzebujesz już pliku beans.xml. patrz docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch
1
Dzięki JavaEE7 nie potrzebujesz pliku beans.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm (poprawny link) blogs.oracle.com/theaquarium/entry/… (Domyślne włączenie CDI w Javie EE 7)
M. Atif Riaz
2

Używałem CDI w GlassFish 3.0.1, ale aby to zadziałało, musiałem zaimportować szkielet Seam 3 (Weld). To działało całkiem nieźle.

W GlassFish 3.1 CDI przestał działać, a Seam Weld przestał z nim działać. Otworzyłem błąd w tym, ale nie widziałem go jeszcze naprawionego. Musiałem przekonwertować cały mój kod na używanie adnotacji javax.faces. *, Ale planuję wrócić do CDI, gdy zaczną działać.

Zgadzam się, że powinieneś użyć CDI, ale jeden problem, którego nie widziałem jeszcze rozwiązany, dotyczy tego, co zrobić z adnotacją @ViewScoped. Mam dużo kodu, który od tego zależy. Nie jest jasne, czy @ViewScoped działa, jeśli nie używasz z nim @ManagedBean. Byłbym wdzięczny, gdyby ktokolwiek mógł to wyjaśnić.

AlanObject
źródło
-1

Jeden dobry powód, aby przejść na CDI: możesz mieć wspólny zasób o zasięgu sesji (na przykład profil użytkownika), który byłby przypisany @Injectzarówno do komponentów bean zarządzanych przez JSF, jak i usług REST (np. Jersey / JAX-RS).

Z drugiej strony @ViewScopedjest to nieodparty powód, aby trzymać się JSF @ManagedBean- szczególnie w przypadku wszystkiego, co ma znaczący AJAX. W CDI nie ma standardowego zamiennika.

Wygląda na to, że może mieć pewne wsparcie dla @ViewScopedadnotacji typu a dla fasoli CDI, ale osobiście nie bawiłem się tym.

http://seamframework.org/Seam3/FacesModule

wrschneider
źródło