Gdzie używać EJB 3.1 i CDI?

120

Tworzę produkt oparty na Java EE, w którym używam GlassFish 3 i EJB 3.1.

Moja aplikacja zawiera ziarna sesji , harmonogram i korzysta z usług internetowych. Niedawno dowiedziałem się o Apache TomEE , który obsługuje funkcje Contexts and Dependency Injection (CDI) . Pojemnik GlassFish obsługuje również CDI.

Czy mogę wymienić ziarna sesji, jeśli nie potrzebuję żadnej funkcji, której CDI również nie zapewnia? A jeśli wtedy, jakie korzyści mogę uzyskać?

Dhrumil Shah
źródło

Odpowiedzi:

409

Tak, możesz dowolnie mieszać zarówno CDI, jak i EJB i osiągnąć świetne rezultaty. Wygląda na to, że używasz @WebServicei @Schedule, co jest dobrym powodem do dodania EJB do miksu.

Istnieje wiele nieporozumień, więc oto kilka ogólnych informacji na temat EJB i CDI, ponieważ odnoszą się do każdego z nich razem.

EJB> = CDI

Zauważ, że EJB to fasola CDI i dlatego mają wszystkie zalety CDI. Odwrotna sytuacja nie jest (jeszcze). Więc zdecydowanie nie nabieraj nawyku myślenia „EJB kontra CDI”, ponieważ ta logika naprawdę przekłada się na „EJB + CDI kontra CDI”, co jest dziwnym równaniem.

W przyszłych wersjach Java EE będziemy kontynuować ich dostosowywanie. Co dostosowanie środków jest umożliwienie ludziom robić to, co już może zrobić, po prostu bez @Stateful, @Statelesslub @Singletonadnotacji na szczycie.

EJB i CDI w terminach wdrożenia

Ostatecznie EJB i CDI mają tę samą podstawową konstrukcję, że są komponentami proxy. Kiedy otrzymujesz odniesienie do fasoli EJB lub CDI, nie jest to prawdziwa fasola. Raczej przedmiot, który otrzymujesz, jest fałszywy (proxy). Kiedy wywołujesz metodę na tym fałszywym obiekcie, wywołanie trafia do kontenera, który wyśle ​​wywołanie przez przechwytywacze, dekoratory itp., A także zajmie się wszelkimi transakcjami lub kontrolami bezpieczeństwa. Gdy to wszystko jest zrobione, wywołanie w końcu trafia do rzeczywistego obiektu, a wynik jest przesyłany z powrotem przez proxy do wywołującego.

Różnica polega tylko na tym, jak rozwiązany jest obiekt, który ma zostać wywołany. Przez „rozwiązany” rozumiemy po prostu, gdzie i jak kontener szuka rzeczywistej instancji do wywołania.

W CDI kontener wygląda w „zakresie”, który w zasadzie jest hashemem, który istnieje przez określony czas (na żądanie @RequestScoped, na sesję HTTP @SessionScoped, na aplikację @ApplicationScoped, konwersację JSF @ConversationScopedlub na implementację zakresu niestandardowego).

W EJB pojemnik sprawdza również hashmap, jeśli ziarno jest typu @Stateful. @StatefulFasoli mogą również korzystać z żadnej z powyższych opisów zakresu powodując jej żyć i umierać z wszystkich innych ziaren w zakresie. W EJB @Statefuljest zasadniczo fasolą „o dowolnym zakresie”. Jest @Statelessto w zasadzie pula instancji - otrzymujesz instancję z puli na czas trwania jednego wywołania. Zasadniczo @Singletonjest@ApplicationScoped

Tak więc na podstawowym poziomie wszystko, co można zrobić z ziarnem „EJB”, powinno być w stanie zrobić z ziarnem „CDI”. Pod kołdrą strasznie trudno je odróżnić. Cała instalacja hydrauliczna jest taka sama, z wyjątkiem sposobu rozwiązywania przypadków.

Obecnie nie są one takie same, jeśli chodzi o usługi, które kontener będzie oferował podczas wykonywania tego proxy, ale jak mówię, pracujemy nad tym na poziomie specyfikacji Java EE.

Uwaga dotycząca wydajności

Zignoruj ​​wszelkie „lekkie” lub „ciężkie” obrazy mentalne, które możesz mieć. To wszystko marketing. Mają w większości ten sam projekt wewnętrzny. Rozdzielczość instancji CDI jest być może nieco bardziej złożona, ponieważ jest nieco bardziej dynamiczna i kontekstowa. W porównaniu z tym, rozdzielczość instancji EJB jest dość statyczna, głupia i prosta.

Z punktu widzenia implementacji w TomEE mogę powiedzieć, że różnica w wydajności między wywołaniem EJB a wywołaniem komponentu bean CDI jest prawie zerowa.

Domyślnie POJO, następnie CDI, a następnie EJB

Oczywiście nie używaj CDI ani EJB, gdy nie ma korzyści. Dodaj CDI, gdy zaczniesz chcieć zastrzyku, zdarzeń, przechwytywaczy, dekoratorów, śledzenia cyklu życia i tym podobnych. To jest większość czasu.

Poza tymi podstawami, istnieje szereg przydatnych usług kontenerowych masz tylko możliwość korzystania jeśli dokonać fasoli CDI również EJB dodając @Stateful, @Statelesslub @Singletonna nim.

Oto krótka lista sytuacji, w których wyłamałem się z EJB.

Korzystanie z JAX-WS

Odsłanianie JAX-WS @WebService. Jestem leniwy. Gdy @WebServicejest to również EJB, nie musisz go wymieniać i mapować jako serwletu w web.xmlpliku. To dla mnie praca. Dodatkowo mam możliwość korzystania z dowolnej innej funkcji wymienionej poniżej. Więc to dla mnie oczywiste.

Dostępne @Statelessi @Singletontylko.

Korzystanie z JAX-RS

Udostępnianie zasobu JAX-RS za pośrednictwem @Path. Nadal jestem leniwy. Gdy usługa RESTful jest również EJB, ponownie otrzymujesz automatyczne wykrywanie i nie musisz dodawać jej do Applicationpodklasy JAX-RS ani niczego podobnego. Poza tym mogę udostępnić dokładnie to samo ziarno, co @WebServicejeśli chcę, lub użyć dowolnej z wymienionych poniżej wspaniałych funkcji.

Dostępne @Statelessi @Singletontylko.

Logika uruchamiania

Załaduj przy uruchomieniu przez @Startup. Obecnie nie ma odpowiednika w CDI. W jakiś sposób przegapiliśmy dodanie czegoś w rodzaju AfterStartupzdarzenia w cyklu życia kontenera. Gdybyśmy to zrobili, po prostu moglibyśmy mieć @ApplicationScopedfasolkę, która nasłuchuje, a to byłoby w rzeczywistości takie samo jak @Singletonwith @Startup. Jest na liście dla CDI 1.1.

Dostępne @Singletontylko dla.

Praca równoległa

@Asynchronouswywołanie metody. Uruchamianie wątków jest niemożliwe w żadnym środowisku po stronie serwera. Zbyt wiele wątków to poważny zabójca wydajności. Ta adnotacja umożliwia zrównoleglenie czynności wykonywanych przy użyciu puli wątków kontenera. To jest niesamowite.

Dostępne @Stateful, @Statelessa @Singleton.

Planowanie pracy

@Schedulelub ScheduleExpressionjest w zasadzie cronem lub Quartzfunkcjonalnością. Również super. Większość pojemników po prostu używa do tego kwarcu pod pokrywami. Większość ludzi nie wie jednak, że planowanie pracy w Java EE jest transakcyjne! Jeśli zaktualizujesz bazę danych, a następnie zaplanujesz pracę i jedna z nich się nie powiedzie, obie zostaną automatycznie wyczyszczone. Jeśli EntityManagerpołączenie utrwalania nie powiedzie się lub wystąpi problem z opróżnianiem, nie ma potrzeby rozplanowywania pracy. Tak, transakcje.

Dostępne @Statelessi @Singletontylko.

Korzystanie z EntityManagers w transakcji JTA

Powyższa uwaga dotycząca transakcji wymaga oczywiście korzystania z usługi JTAmanaged EntityManager. Możesz ich używać ze zwykłym "CDI", ale bez transakcji zarządzanych przez kontener może to być naprawdę monotonne powielanie UserTransactionlogiki zatwierdzania / wycofywania.

Dostępny dla wszystkich komponentów Java EE tym CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, itd @TransactionAttributeadnotacji jest jednak dostępna @Stateful, @Statelessa @Singletontylko.

Zarządzanie JTA EntityManager

EXTENDEDUdało EntityManagerpozwala zachować EntityManagerotwarty od JTAtransakcji i nie stracić danych w pamięci podręcznej. Dobra funkcja we właściwym czasie i miejscu. Używaj odpowiedzialnie :)

Dostępne @Statefultylko dla.

Łatwa synchronizacja

Kiedy potrzebujesz synchronizacji, adnotacje @Lock(READ)i @Lock(WRITE)są całkiem doskonałe. Umożliwia bezpłatne jednoczesne zarządzanie dostępem. Pomiń całą instalację wodociągową ReentrantReadWriteLock. W tym samym wiadrze jest @AccessTimeout, który pozwala określić, jak długo wątek powinien czekać, aby uzyskać dostęp do instancji fasoli, zanim się zrezygnuje.

Dostępne @Singletontylko dla fasoli.

David Blevins
źródło
32
Dobry Boże David :) Myślę, że to zakryłeś.
LightGuard
7
Dziękuję za tę odpowiedź. Oczyściłeś moją głowę i połączyłeś wiele kropek.
Thupten
7
To zdecydowanie najlepsze wyjaśnienie na ten temat, jakie kiedykolwiek czytałem. Obejmuje również prawie wszystkie ważne aspekty EJB w rzeczywistych zastosowaniach. Świetna robota!!
nanoquack
3
Bardzo zrozumiałe i Adam nie myli się w ścisłych prawniczych kategoriach, ale to rozróżnienie jest dyskusyjne. Specyfikacja mówi, że instancja EJB nie jest kontekstowa, ale później mówi, że odniesienie (proxy) do EJB jest kontekstowe. Cykl życia Stateful Bean jest kontrolowany całkowicie przez odniesienie (proxy), więc kiedy kontener CDI kontroluje to odwołanie (proxy), matematyka wygląda tak samo - Stateful EJBs mogą efektywnie być kontekstowe.
David Blevins
3
Napisałeś to podczas przerwy na lunch w TESLA?
Edison,
2

Jeśli naprawdę nie używasz żadnej z funkcji ejb 3.1, odpowiedź jest prosta. ale zgadnij, że twoje questiion wskazuje, że podejrzewasz, że istnieją koncepcje ejb 3.1, z których korzystasz, nie będąc ich świadomymi. jednym z przykładów może być to, że kontener może przechowywać pulę slsb gotową do użycia, dzięki czemu jms i połączenia z bazą danych nie muszą być wstrzykiwane jako część żądania

Aksel Willgert
źródło