Jeden z kľúčových aspektov EJB architektúry je distribuovanosť. Pod týmto výrazom sa rozumie, že nie všetky objekty musia bežať v rámci tej istej inštancie JVM (Java Virtual Machine). Otázka teda je, ako môžeme z objektu A, existujúceho v rámci jednej JVM, volať metódy objektu B, nachádzajúceho sa v úplne inej JVM? Odpoveďou z pohľadu EJB je použiť Remote Method Invocation (RMI).

EJB Client

Skôr ako prejdeme na použitie RMI a EJB, povieme si niečo o klientovi EJB. EJB klient je objekt, ktorý potrebuje komunikovať s EJB za účelom vykonania určitých úloh. Zjednodušene povedané, EJB komponent poskytuje služby a EJB klient je jedným z ich konzumentov. Poznáme dva typy klientov.

Local EJB Client

Lokálny klient je vždy v rámci rovnakej JVM ako EJB. V tomto prípade sa metódy daného EJB volajú klasickým spôsobom, tak ako je to bežné. Avšak takéto odkrytie EJB lokálnemu klientovi je málo používané a môže skrývať určité riziká. Aby takýto systém fungoval, musí byť medzi klientom a enterprise beanom kolokácia, teda prepojenie. Toto prepojenie sa zabezpečí spoločným deploymentom na rovnakej JVM. Na druhej strane, táto koncepcia má pozitívny vplyv na výkonnosť vašej aplikácie. Všeobecne sa odporúča, aby lokálnym klientom jednej EJB bola iná EJB.

Remote EJB Client

Vzdialený klient (RC) obvykle nie je umiestnený v tej istej JVM ako EJB komponent, ale môže sa fyzicky nachádzať na inom počítači a bežať na inej JVM. RC sa principiálne nemusí starať o to, kde v skutočnosti sa EJB, ku ktorej pristupuje, nachádza.

RC môže byť iný EJB komponent umiestnený v rámci tej istej JVM alebo v rámci inej JVM, ale môže to byť aj webovská aplikácia, applet, Java desktop aplikácia Java MIDlet a podobne. RC môže byť dokonca aj non-Java aplikácia, napríklad CORBA aplikácia napísaná v C++. Vzdialený klient používa špeciálny protokol na prístup k EJB, ktorý je odlišný od klasickej sémantiky. V nasledujúcej časti sa budeme venovať tomuto protokolu detailnejšie.

Použitie RMI na komunikáciu s EJB

Remote Method Invocation (RMI) je technológia, ktorá už dávnejšie bola využívaná v spojitosti s CORBA alebo DCOM. Pre Javu existuje verzia nazvaná Java RMI, pričom ide o objektový protokol špeciálne navrhnutý tak, aby umožnil komunikovať objektom nachádzajúcim sa v rôznych JVM. Inými slovami, Java RMI je určené na Java-to-Java komunikáciu.

Java RMI vytvára určité „maskovanie“, pri ktorom to z pohľadu klientského objektu vyzerá tak, ako keby vzdialený objekt bežal na tej istej JVM, i keď v skutočnosti beží na inej. Táto transparentnosť je zabezpečovaná prostredníctvom dvoch komponentov – stub a skeleton.

Stub a Skeleton

Ak potrebujete ručne implementovať funkcionalitu volania vzdialených metód, bude si to vyžadovať veľa práce „nadčas“. Našťastie existujú nástroje, ktoré umožňujú prekontrolovať vaše triedy a vygenerovať kód, potrebný na realizáciu vzdialených volaní. Takto je možné jednoducho zmenšiť komplexnosť vašich tried a zároveň oddeliť biznis logiku od infraštruktúry implementácie Java RMI. Toto je aj zmysel existencie prvkov označovaných ako „stub“ a „skeleton“.

Stub je proxy objekt, plne zodpovedný za spracovanie volania vzdialených metód. Jeho úlohou je ukrývať fakt, že klient v skutočnosti komunikuje so vzdialeným objektom a zvyčajne presne kopíruje metódy tohto objektu. V skratke sa dá napísať, že stub objekt vykonáva nasledovné činnosti v danom poradí:

  1. Inicializuje spojenie so vzdialeným objektom.
  2. Prečíta a odošle parametre určené vzdialenej metóde.
  3. Čaká na výsledok volania vzdialenej metódy.
  4. Prečíta si prijatý výsledok alebo vzniknutú výnimku.
  5. Predá túto hodnotu alebo výnimku klientovi.

Každý vzdialený objekt môže mať vytvorený odpovedajúci skeleton objekt, ktorý je s ním asociovaný. Skeleton objekt je zodpovedný za presmerovanie klientského volania na správnu inštanciu vzdialeného objektu. Obvykle existuje jeden skeleton pre jeden vzdialený objekt. Avšak od nástupu Java 2 platformy už nie je nutné skeleton objekt používať. A to preto, že je možné napísať si vlastnú Java triedu, ktorá bude sama obsluhovať a presmerovávať požiadavky na inštancie vzdialených objektov. Napriek tomu si myslím, že je dobré pri použití Java RMI počítať so skeleton objektmi. Aj keď konečná implementácia môže byť odlišná.

Keď skeleton objekt obdrží požiadavku, vykoná nasledovné:

  1. Prečíta parametre určené vzdialenej metóde.
  2. Zavolá príslušnú metódu a predá jej parametre.
  3. Zapíše a odošle obdržaný výsledok alebo výnimku klientovi.

Pre každý EJB komponent, ktorý má byť dostupný vzdialeným klientom, bude vytvorený príslušný stub a prípadne aj skeleton objekt. Stub aj skeleton sú obvykle vytvárané v procese nasadenia EJB komponentu, pomocou nástrojov, ktoré sú súčasťou EJB kontajnera. Akým spôsobom bude stub objekt pri RMI volaniach použitý a či vôbec bude skeleton vytvorený, záleží na samotnom EJB kontajnery. Programátor sa obvykle vôbec nemusí starať, ako celý systém pracuje.

Java RMI System

Java RMI cez JRMP

Aby sme si urobili predstavu, vytvoríme si príklad, pri ktorom si ukážeme mágiu použitia Java RMI. Aby som vás však príliš nevystrašil, ukážeme si použitie Java RMI s využitím protokolu Java Remote Method Protocol (JRMP). Okrem tohto protokolu je možné použiť aj Internet Inter-Orb Protocol (IIOP) ako komunikačnú vrstvu.

Na začiatok si vytvoríme objekt, ktorý bude slúžiť ako vzdialený objekt. Tento objekt bude implementovať rozhranie, obsahujúce len jedinú metódu. Nasledovný výpis obsahuje rozhranie implementované naším objektom:

Výpis súboru RMIExample.java
Výpis súboru RMIExample.java

Ako vidíte, naše rozhranie deklaruje len jednu metódu getMessage(). Toto rozhranie rozširuje ďalšie rozhranie s názvom java.rmi.Remote. Samozrejme nesmieme zabudnúť na vznik možných výnimiek, ktoré sa môžu vyskytnúť pri vzdialenom volaní metód. Komunikácia sa totiž bude realizovať cez niekoľko sieťových vrstiev. Z toho dôvodu musia všetky metódy deklarované v remote rozhraní zahrnúť výnimku java.rmi.RemoteException.

V nasledujúcom kroku si vytvoríme triedu, ktorá bude uvedené rozhranie implementovať. Táto trieda bude predstavovať vzdialený objekt, ktorý môže prijať vzdialené volania od klienta z inej JVM. Nasledujúci výpis znázorňuje túto triedu:

Výpis súboru RMIExampleImpl.java
Výpis súboru RMIExampleImpl.java

Uvedený výpis je pomerne priamočiary. Naša trieda rozširuje triedu java.rmi.server.UnicastRemoteObject a implementuje nami vytvorené rozhranie RMIExample. Rozširovaná trieda zabezpečuje a stará sa o množstvo úloh súvisiacich so sieťovou komunikáciou. Implementácia rozhrania spočíva v implementácii metódy getMessage(), ktorá vráti jednoduchý textový reťazec. Všimnite si, že implementácia neobsahuje ošetrenie výnimky RemoteException. Je to tým, že za celý proces spracovania požiadaviek na vzdialené objekty, sú zodpovedné komponenty stub a skeleton.

Teraz prišiel čas, aby sme sa pozreli, ako triedy komponentov stub a skeleton vlastne vyzerajú. Nebude to však pekný pohľad. To ale nevadí, pretože len málokedy budete potrebovať priamo editovať ich zdrojový kód. Na vygenerovanie tried stub a skeleton môžete použiť Java SDK, konkrétne nástroj rmic, ktorý nájdete v zložke /bin. Tomuto Java RMI kompilátoru treba predať vopred skompilované triedy, ktoré implementujú java.rmi.Remote. Nezabudnite použiť prepínač -keep, aby kompilátor nevymazal prechodne vytvorené zdrojové súbory.

JavaRMI compilator console

Kompilátor rmic nám vytvoril dva nové zdrojové súbory, ktoré hneď aj skompiloval. Nasleduje výpis obsahu týchto tried:

Výpis súboru RMIExampleImpl_Stub.java
Výpis súboru RMIExampleImpl_Stub.java

Výpis súboru RMIExampleImpl_Skel.java
Výpis súboru RMIExampleImpl_Skel.java

Napriek uvedenému, každý dodávateľ EJB servera môže implementovať podporu pre RMI mierne odlišným spôsobom, avšak princíp by mal zostať rovnaký. Môžeme si ho ešte raz stručne opísať – v prvom kroku je treba vytvoriť rozhranie obsahujúce všetky biznis metódy, ktoré majú byť implementované na vzdialenom objekte. Toto rozhranie sa označuje ako component interface a v prípade RMI ho voláme remote interface. Implementácia tohto rozhrania (remote object, EJB), je použitá na vygenerovanie tried stub a skeleton. Následne sa môžu tieto komponenty nasadiť na server.

Shrnutie

Myslím, že najdôležitejším faktom, ktorý si treba uvedomiť po prečítaní tohto článku je, že keď zo vzdialeného klienta zavoláte nejakú metódu patriacu EJB objektu, v skutočnosti nezavoláte túto metódu priamo, ale sprostredkovane.

Ak máte záujem o bližší pohľad na stub a skeleton, stiahnite a prezrite si použité príklady.

Odkazy a zdroje

  • Introduction to RMI – tu nájdete relatívne dosť zaujímavých a fundovaných článkov, venujúcich sa rôznym oblastiam Javy (jedným z nich je aj článok o Java RMI, rozčlenený do niekoľkých kapitol)

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět