13 listopada 2008

W sprawie EJB 3.0 - Jak pakować komponenty w plik .jar?

Dostałem dzisiaj wiadomość, w której padło pytanie o sposób dystrybucji komponentów EJB.

Studiuje sobie ksiazke Enterprise JavaBeans wydawnictwa O'Reilly o komponentach, oczywiscie jeszcze jestem w powijakach ale juz sporo(wg mnie:-) ) rozumiem. Nurtuje mnie jednak pytanie jak pakowac komponenty w plik .jar ktory pozniej wdrozymy na serwer aplikacji. Tzn czy idea jest umiesczanie wszystkie komponentow w jednym pliku .jar jako calej aplikacji np sklep.jar(zapewne nie bo po co bylby .ear ale to tylko moj punkt widzenia malego czlowieczka raczkujacego w technologii EE) jako calej aplikacji czy tez kazdego komponentu oddzielnie, czy umieszczac wszystkie komponenty encyjne w jednym sesyjne w drugim itd, a moze komponenty spojne ze soba logicznie czyli np komponent sesyjny bezstanowy majacy w sobie funkcje odnoszace sie do komponentu sesyjnego. Troche chaotycznie to wszystko napisalem ale mam nadzieje Jacku ze mi wybaczysz moja niewiedze w tej technologii.

I już zacząłem moją krótką odpowiedź, aż przypomniałem sobie podobne pytanie od kogoś innego, więc padło na odpowiedź publiczną na moim blogu. Oto ona.

Każde ziarno EJB w EJB 3.0 to fizycznie dwa pliki class - interfejs (biznesowy w sensie EJB) oraz jego realizacja (implementacja). Klasy w javie umieszcza się w pakietach (zalecane jest, aby nie korzystać z pakietu domyślnego, tj. zadeklarowanego, gdy nie korzystamy ze słowa kluczowego package). Rozmieszczenie klas w pakietach nie ma żadnego wpływu na ich zarządzanie przez kontener EJB. Kontener jest w tym względzie neutralny. Mając interfejs oraz klasę w wybranych pakietach (dalej nazwijmy je artefaktami programistycznymi) przychodzi do ich organizacji w postaci ich umiejscowienia w odpowiadającym pakietowi katalogu lub plikowi jar. Zalecane jest, aby do dystrybucji naszej aplikacji stosować format jar. Ile i jakie ziarna EJB będą w pojedyńczym pliku jar nie ma kompletnie znaczenia. Może być tak, że dla każdej pary interfejs+implementacja stworzymy dedykowane im pliki jar. Może być też tak, że wszystkie pary będą umieszczone w pojedyńczym, obszernym pliku jar. Z punktu widzenia EJB 3.0 nie ma to żadnego znaczenia, poza faktem ich widoczności w ładowarce klas dla naszej aplikacji.

Każdy serwer aplikacyjny (w tym również kontener EJB) tworzy sieć (graf skierowany w postaci drzewa) ładowarek klas, gdzie dla pojedyńczego pliku jar mamy dedykowaną ładowarkę. Jeśli ta ładowarka klas obejmuje wszystkie klasy uczestniczące w pracy ziarna EJB, przynajmniej interfejs oraz klasa realizująca, wszystko będzie w należytym porządku. Istnieje "pojemniejszy" format organizacji artefaktów aplikacji korporacyjnych w Java EE 5 - plik ear. W nim możemy umieszczać pliki jar i inne (na chwilę obecną nieistotne). Plik ear tworzy przestrzeń widoczności (poprzez dedykowaną ładowarkę klas) dla wszystkich plików jar, które są w jego strukturze. Jeśli zdarzy się stworzyć plik sklep-interfejs.jar oraz sklep-implementacja1.jar to tylko w sytuacji dostępności pierwszego możemy oczekiwać poprawnej pracy ziarna EJB reprezentowanego przez drugi plik jar. Najczęściej jest to realizowane poprzez skorzystanie z pliku ear jako formatu dystrybucji naszych ziaren EJB.

Można zapytać, dlaczego warto zadać sobie trud, aby dzielić naszą aplikację, opartą o kilka ziaren EJB, na kilka plików jar, np. jeden per ziarno, potencjalnie z plikiem zawierającym interfejs jako osobny plik jar? Oczywiście zwiększa to modularność aplikacji. Jakkolwiek z punktu widzenia specyfikacji Java EE 5 nie jest to prawdziwe stwierdzenie, gdyż w "gołej" Javie reguły rządzące widocznością klas nie są zbyt wyrafinowane i czy jesteś w jednym pliku jar, czy w wielu, nie ma to znaczenia (zakładając ich widoczność w ładowarce klas), to już w środowiskach OSGi tak nie jest. Ma to znaczenie? Oczywiście nie dla...niekorzystających z OSGi. W samej korporacyjnej javie umieszczenie jarów na ścieżce klas (dosłownie, w systemie plików, lub wirtualnie poprzez umieszczenie ich w tej samej ładowarce klas) już wystarczy. Modularność w Java EE 5 mamy przez zastosowanie ziaren EJB, a ich fizyczne rozmieszczenie na jeden czy kilka jarów nie ma żadnego znaczenia. Muszą być po prostu dostępne i tyle. W bardziej restrykcyjnych środowiskach, jak OSGi, podział na większą liczbę plików jar pozwala na stworzenie aplikacji bardziej modularnie patrząc na jej fizyczną strukturę. W OSGi jar tożsamy jest z podstawowym bytem OSGi - pakunkiem. Dla OSGi plik jar jest pewnym bytem, podczas gdy dla EJB 3.0 jest niczym (jest to jedynie format dystrybucji dla języka Java, ale EJB 3.0 już nie wie, ile i czy w ogóle korzystaliśmy z pliku jar lub symulowaliśmy go strukturą podobną do pliku jar - "rozpakowany jar", czy po prostu umieściliśmy odpowiednio wiele na ścieżce klas). Możemy uruchomić jeden pakunek OSGi z interfejsem (=jeden plik jar), a drugi pakunek dostarczyć później i zmieniać ich widoczność dynamicznie, podczas działania aplikacji. W EJB 3.0 nie ma już takiej funkcjonalności, aczkolwiek sam serwer może to udostępniać, np. będąc oparty o OSGi lub inny mechanizm.

Miało być krótko i mimo, że zahaczyłem o OSGi sądzę, że było. Pytania?

3 komentarze:

  1. Cześć,

    Nie tyle pytanie, co komentarz, że akurat zagadnienie dystrybucji (deployment) to jest jedna z dużych przewag JEE nad OSGi (a także nad Spring). Zarówno OSGi, jak i Spring w zasadzie nie mają standardowego formatu dystrybucji, nadającego się dla większych aplikacji. Spring korzysta w tym zakresie z tego co daje deployment aplikacji webowych (czyli .WAR) oraz JEE (czyli "EJB.jar" i EAR). OSGi ma model JAR, który jest delikatnie mówiąc ubogi. Spring dm Server wnosi niestandardowe rozszerzenie czyli .PAR, ale stoi ono moim zdaniem w wielkiej sprzeczności z duchem czasów i filozofii Spring Framework, bo jest specyficzne dla Spring dm Server. Nie widać też, aby ktokolwiek inny (tzn. inni liczący się gracze na rynku serwerów aplikacyjnych) adaptował ten format. Politycznie, to na razie SpringSource rozgrywa to tak źle, jak pewien polityk w naszym pięknym kraju...

    Mówiąc o tym, że dany model deployment'u jest "ubogi", mam na myśli nie tylko sam format archiwum aplikacji (EAR, WAR, RAR, SAR, ...), ale także chociażby deployment plans (http://jcp.org/en/jsr/detail?id=88). Klienci z którymi ja mam kontakt (czyli użytkownicy WebLogic) dosyć mocno używają tej funkcjonalności. W skrócie: w deployment plans chodzi o to, że przed deployment'em aplikacji administrator może nadpisać wybrane parametry znajdujące się w deployment deskryptorach aplikacji (a także w innych miejscach). To nadpisywanie odbywa się oczywiście bez potrzeby otwierania archiwum aplikacji, dekompresji plików i tym podobnych zabiegów. Dla przykładu - dzięki deployment plans, całkiem trywialne jest zrobienie typowej rzeczy, czyli przenoszenia aplikacji pomiędzy środowiskami Dev -> Test -> QA -> Produkcja, bez zmiany samej aplikacji.

    Tak jak napisał Jacek, poza samym JEE, także poszczególne serwery JEE dają sporo ułatwień w modelu dystrybucji i wiele z tego, co będzie kiedyś w ramach OSGi, można zrobić bezpieczniej już dzisiaj, nie czekając na przebudowę JEE w kierunku OSGi. Przykłady z mojego podwórka - można mieć wiele wersji aplikacji działających równocześnie - http://download.oracle.com/docs/cd/E12840_01/wls/docs103/deployment/redeploy.html#wp1020276. Można współdzielić biblioteki, w tym je wersjonować, pomiędzy wieloma aplikacjami (nie kupuję tej wizji rzeczywistości przedstawianej m.in. przez autorów Spring dm Server, że kopiuje się JARy do aplikacji i robi się deployment takich "spuchniętych" aplikacji - ja widzę przeważnie inne praktyki) - http://download.oracle.com/docs/cd/E12840_01/wls/docs103/programming/libraries.html. Można trochę ułatwić sobie życie z classloading'iem - http://download.oracle.com/docs/cd/E12840_01/wls/docs103/programming/classloading.html#wp1097187. Stosując takie rozwiązania można żyć łatwiej czekając, aż "OSGi dla normalnych ludzi", czyli deweloperów i administratorów aplikacji okrzepnie (dla piszących serwer aplikacyjny OSGi jest pewnie już dzisiaj strawne, ale to są inni ludzie ;-). Można zresztą znaleźć wypowiedzi z praktycznie każdego takiego "obozu", że nawet i oni sporo rzeczy i tak muszą sami do OSGi - i jego implementacji - dopisywać).

    Tym, którzy - czasem trochę manipulując rzeczywistością - pieją peany o OSGi i jego gotowości JUŻ DZISIAJ (!) do produkcyjnego wykorzystania, zżymając się przy tym na "syfiastość" J2EE/JEE, akurat zagadnienie deployment'u aplikacji polecałbym do głębszego porównywania... Jak czytam artykuły prasowe komentujące rzekomą obsługę OSGi w Glassfish v3 Prelude, to mnie to rozkłada, jak wciąż łatwo daje się manipulować rzeczywistość paroma buzzword'ami...

    Pozdrawiam,
    Waldek Kot
    http://jdn.pl/blog/88

    OdpowiedzUsuń
  2. Moje ostatnie doświadczenia z jednym z serwerów aplikacyjnych (JBOSS 5) wykazały że to czy aplikacja jest wdrażana jako jeden jar czy wiele osobnych jarów może mieć kluczowe znaczenie. A mianowicie okazuje się że nie jesteśmy w stanie wstrzelić adnotacją @EJB referencji beana sesyjnego do innego beana jeżeli oba znajdują się w osobnych jarach. http://www.jboss.com/index.html?module=bb&op=viewtopic&t=148777

    OdpowiedzUsuń
  3. Strong words from someone trying to bypass spec scoping by injecting across unrelated JARs/EARs. To powinno wyjaśnić wszystko. JBAS w wielu miejscach pozwala na pewne nieścisłości względem specyfikacji i właśnie jedną z nich mogłeś doświadczyć. Umieść je w EARze i sprawa *powinna* się rozwiązać.

    OdpowiedzUsuń