Enterprise JavaBeans

A Wikipédiából, a szabad enciklopédiából

Az Enterprise JavaBean-ek (EJB) moduláris vállalati alkalmazásokban használt szerveroldali komponensek. Általában az üzleti logika implementációját tartalmazzák. Az EJB specifikációt eredetileg az IBM adta ki 1997-ben. Később, 1999-ben, a Sun Microsystems is elfogadta, alkalmazta (EJB 1.0 és 1.1), és tovább terjesztették a Java Community Process alatt mint JSR19, JSR152, JSR220 és JSR318.[1]

Története[szerkesztés | forrásszöveg szerkesztése]

Az EJB 1.0 specifikációt az IBM fejlesztette ki 1997-ben, majd a Sun Microsystems 1999-ben adoptálta.[2] A Java Community Process keretében fejlesztették tovább specifikációt és Java Specification Request dokumentumokként kerültek nyilvánosságra az újabb verziók:

Verzió Specifikáció Kiadás éve
EJB 1.0 1998
EJB 1.1 1999
EJB 2.0 JSR 19 2001
EJB 2.1 JSR 153 2003
EJB 3.0 JSR 220 2006
EJB 3.1 JSR 318 2009
EJB 3.2 JSR 345 2013

EJB Specifikáció[szerkesztés | forrásszöveg szerkesztése]

Az EJB specifikációt arra tervezték, hogy egy alapvető módszer legyen a vállalati alkalmazásokban levő back-end üzleti kódok megvalósítására. Ezekben a kódokban gyakran ugyanazok a hibák jelentek meg, és ezeket a problémákat a programozók újra és újra ugyanúgy oldották meg. Az EJB-t arra hozták létre, hogy kezelje a perzisztenciát, a tranzakciók integritását és az adatvédelmet úgy, hogy a programozók szabadon koncentrálhassanak a megoldandó problémákra.

Az EJB specifikáció részletezi egy alkalmazás szolgáltatásait:

Mi több, az EJB specifikáció azokat a kötelességeket írja le, amit az EJB konténer és maga az EJB tartalmaz, mint ahogy azt is, hogy hogyan kell telepíteni az EJB konténert. Megjegyzendő, hogy a jelenlegi EJB specifikáció nem részletezi többé, hogy egy alkalmazás hogyan gondoskodik a perzisztenciáról (egy olyan feladatról, ami a JPA specifikáció delegáltja), de ehelyett részletezi, hogy az üzleti logika könnyedén integrálható a perzisztencia szolgáltatásokkal, amiket a kiszolgáló alkalmazás nyújt.

A megjelenés utáni csalódás[szerkesztés | forrásszöveg szerkesztése]

A problémák gyorsan előkerültek, ennek következtében az EJB hírneve kopni kezdett. Néhány API fejlesztő úgy gondolta, hogy az EJB API-ja sokkal összetettebb, mint amihez hozzá voltak szokva. A rengeteg ellenőrzött kivétel, igényelt interfész és a bean osztályok absztrakt osztályként való implementálása szokatlan és természetellenes volt a legtöbb programozó számára. Ismert, hogy az EJB szabvány nagyon összetett problémákat próbált kezelni. Ilyen pl. az objektum-relációs leképzés vagy a tranzakció épség. Ennek ellenére sok programozó az API-t is hasonló, vagy még nehezebbnek vélte, így alakult ki az a széleskörű felfogás, miszerint az EJB által bemutatott összetettség nem nyújt igazi hasznot.

Mi több, a cégek úgy találták, hogy az EJB használata az üzleti logikában rontotta a teljesítményt. Ez azért történhetett, mert az eredeti specifikáció csak a CORBA-n, esetleg más hasonló protokollokon keresztül engedte a távoli eljárás hívást (és opcionálisan minden más eljárást is), annak ellenére, hogy a legtöbb üzleti alkalmazásnak nincs is szüksége az elosztott számítási funkcióra. Az EJB 2.0 specifikáció ennek az aggodalomnak a megszüntetésesre jött létre. Ezt úgy akarták kivitelezni, hogy hozzáadták a helyi interfész koncepcióját, amelyet egyenes úton lehetett hívni anélkül, hogy a többszörös szervereken eloszló alkalmazások által előhozott probléma megjelent volna.

Széles körben az EJB 1.0 által felmerült problémák megoldásaként mutatták be. Bonyolultsága azonban továbbra is hátráltatta az EJB elfogadását. Habár a kiváló fejlesztői környezetek az ismétlődő feladatok automatizálásával megkönnyítették az EJB létrehozását és használatát, ugyancsak ezek az eszközök nem segítették a technológia megtanulását. Ezen felül egy ellenálló mozgalom kezdett kibontakozni a programozók között. A fő eredménye ennek az ellenállásnak az EJB-hez képest könnyűsúlyúnak nevezhető Hibernate és a Spring keretrendszer lett. (A Hibernate a perzisztenciát és az object-relational mapping-et valósítja meg, a Spring framework pedig egy alternatív és kevésbé "bőbeszédű" módot nyújt az üzleti logika kódolásához). Annak ellenére, hogy a nagyobb cégek nem támogatták, ezek a technológiák ismertek lettek, és sok olyan cég kezdte használni őket, amelyek csalódtak az EJB-ben.

Az EJB-t a Java BluePrints, és a Sun Java Pet Store demója támogatta. Az EJB használata vitatható és befolyásoló volt. A Java EE programozók, mint például Rod Johnson, megkíséreltek egy olyan választ létrehozni a Java Pet Store-ra, ami támogatja az EJB használatát, és kiemelten hangsúlyozza annak fontosságát. A Sun létrehozott egy alternatívát, amit Plain Old Java Objects-nek neveztek (POJO). Az új EJB 3.0 használata könnyebb lett az EJB 2.0-nál, és több lehetőséget is nyújtott a fejlesztőknek.

Az EJB újraalkotása[szerkesztés | forrásszöveg szerkesztése]

A cégek egymás között megegyeztek abban, hogy az EJB specifikáció elsődleges előnye, az elosztott alkalmazások tranzakciós épségének biztosítását a legtöbb üzléeti alkalmazás kevéssé használja. Sokkal hasznosabbak voltak a könnyűsúlyú keretrendszerek által nyújtott funkciók. Példa erre a Spring, vagy a Hibernate.

Ennek megfelelően az EJB 3.0 (JSR 220) radikálisan különbözött az ősöktől, és ezt az új mintát követte. Nyilvánvaló a hasonlóság abban a Springgel, ahogy a POJO-kat használja. Továbbá a dependency injectiont is megvalósítja, ami egyszerűsíti a heterogén rendszer felépítését és összekapcsolását. Gavin King a Hibernate megalapítója is részt vett a az EJB 3.0 folyamatában, és a technológia köztudott szószólója. A Hibernate sok jellegzetessége megjelenik a Java Persistence API-ban, ami az entity beanst helyettesíti az EJB 3.0-ban. Az EJB 3.0 erősen az annotációkon alapul, bár megtartotta a korábbi konfigurációs lehetőségeket is.

Ezek az annotációk a Java nyelvhez az 5.0-ás megjelenésével lettek hozzáadva, hogy egy kevéssé bőbeszédű és biztonságosabb kódoló stílust hozzanak létre. Ennek megfelelően a gyakorlatban az EJB 3.0 egy majdnem teljesen új API, ami könnyebb súlyú, és csak kevéssé hasonlít a megelőző EJB specifikációkra.

Példa[szerkesztés | forrásszöveg szerkesztése]

A következő példa azt mutatja be, hogy hogyan is néz ki egy EJB gyakorlatban:

@Local
public interface CustomerServiceLocal {
   void addCustomer(Customer customer);
}
 
@Stateless 
public class CustomerService implements CustomerServiceLocal { 
 
  @PersistenceContext 
  private EntityManager entityManager; 
 
  public void addCustomer(Customer customer) { 
    entityManager.persist(customer); 
  } 
}

A fenti kód egy egyszerű alkalmazás osztály lokális interfész implementációja, melynek segítségével állandó customer objektumot, illetve proxyt hoz létre (az O/R mapping-en keresztül). Az EJB a perzisztenciára koncentrál és az addCustomer() mód tranzakcionális és szálbiztos a beállítások miatt. Ahogy azt láthattuk, az EJB csak a perzisztenciára és az üzleti logikára koncentrál, más egyedi részleteket, felépítést nem ismer.

Az EJB-t osztályokban is lehet használni mint a következő példában is:

@Named
@RequestScoped
public class CustomerBacking {
 
   @EJB CustomerServiceLocal customerService;
 
   public String addCustomer() {
      customerService.addCustomer(customer);
      context.addMessage(...); // abbreviated for brevity
      return "customer_overview";
   }
}

A fenti kódolás egy JSF backing bean-t mutat be, amibe a @EJB annotáció hatására a konténer egy EJB-t injektál. Az addCustomer metódus a felhasználói felület egyes komponenseihez kapcsolódik, mint például egy gomb. Az EJB-vel ellentétben, a backing bean nem tartalmaz semmilyen üzleti logikát vagy perzisztencia kódot, de delegálja az efféle kéréseket az EJB-nek. A backing bean tud olyan egyedi implementációkról is, amiről az EJB-nek nincs tudomása.

EJB típusok[szerkesztés | forrásszöveg szerkesztése]

Az EJB-k három csoportra oszthatók: [3]

Session beanek[szerkesztés | forrásszöveg szerkesztése]

A session bean-ek lehetnek:[4]

Állapotmentesek (stateless)[szerkesztés | forrásszöveg szerkesztése]

Az állapotmentes session bean[5] nem perzisztens bean. Nem tárol állapotot a sessionről, így az egyes hívásai függetlenek. Állapota lehet. Mivel az állapotmentes session bean példányai nem tárolnak a klienstől származó adatot, így a metódusainak végrehajtásához szükséges összes adat a metódusok paramétereiből származik.

Ezek a beanek nem használhatók párhuzamosan,[6] viszont két hívás között ki tudnak szolgálni egy másik klienst is. Hogyha igény lenne a párhuzamos használatra, akkor a két szál külön példányt kap,[7] így az állapotmentes session garantáltan szálbiztos. A metódusok hivatkozhatnak a bean belső állapotára, de nincs arra garancia, hogy két hívás között ne változzon meg az állapota.

Az adminisztrációs költségek csökkentése éredkében a konténer egy készletet tart fent; egy bean egymás után több kliensnek is odaadható. Mivel nem tartanak fenn állapotot, ezért kezelésük egyszerűbb, és kevésbé időigényes, mint az állapottartó session beaneké.

Állapottartók (stateful)[szerkesztés | forrásszöveg szerkesztése]

Az állapottartó beanek[8] üzleti objektumok, amelyek mezőikben tárolják a klienstől kapott információkat, és megőrzik őket az egész session folyamán. Kapcsolatuk szorosabb, mint a kliens és az állapotmentes beaneké; elvben egy munkamenet során egy bean egy klienshez tartozik,[6] ám ha egyszerre sok klienst kell kiszolgálni, akkor a konténer dönthet úgy, hogy a beant állapotának elmentése (passziválás) után egy másik kliensnek ad oda (aktiválás). Ezért fontos, hogy a bean állapota elmenthető, szerializálható legyen.

A bean állapotát a munkamenet végéig őrzi meg. Ekkor a kliens bezárja a kapcsolatot, és a bean állapotának törlése után visszakerül a készletbe. Előfordul, hogy a kliens nem zárja be a munkafolyamatot; ekkor egy idő múlva a konténer elveszi a beant, hogy ne fogyjon el a készlet. Ez az idő a @AccessTimeout annotációval adható meg.[9] Az állapottartó session beanek támogatják a JPA kiterjesztett perzisztencia kontextust.[10]

Példa: Klasszikus példa a bevásárlókocsi, ami számon tartja a munkafolyamat alatt, hogy a vásárló milyen termékeket tett bele, esetleges lockokkal az adatbázisban. A végén a megrendelés zárja a munkamenetet.

Szingletonok (singleton)[szerkesztés | forrásszöveg szerkesztése]

A szingletonok[11][12] olyan üzleti objektumok, amelyek állapota megosztott egy JVM-en belül. A konkurrens hozzáférést alapértelmezetten a konténer kezeli (Container-managed concurrency, CMC), de ez megváltoztatható. Ekkor a beannek magának kell biztosítania, hogy megőrizze állapotának konzisztens voltát (Bean-managed concurrency, BMC). A CMC-nek jelezhetjük a @Lock annotációval, hogy író vagy olvasó lockot igénylünk-e.

A szingleton beanek konkurrensen használt beanek, amelyekből elvben egy példány létezik; gyakorlatilag azonban minden JVM-nek saját példánya van. Alapértelmezetten lustán jönnek létre, de ezt megváltoztathatjuk a @Startup annotációval.

Példa: Cachelés, vagy a napi árlista központi nyilvántartása.

Üzenetvezérelt bean[szerkesztés | forrásszöveg szerkesztése]

Az üzenet vezérelt beanek (MDB) olyan vállalati beanek, amelyek üzenetek aszinkron feldolgozását teszik lehetővé Java EE alkalmazások számára. Többek között a JMS (Java Message Service) kommunikáció magasabb szintű absztrakcióját nyújtja. Feliratkozhat JMS üzenetsorokra vagy témákra, rendszerint a @MessageDriven activationConfig attributumának hatására. Ezek az EJB-hez rendelődnek, hogy lehetővé tegyék az eseményvezérelt feldolgozást.

Eltérően a session beanektől, az MDB-knek nincs interfészük a kliensek számára, és a kliensek nem is kereshetnek ilyen példányt. Az általan figyelt üzenetsorokra vagy témákra érkező üzeneteket dolgozza fel. A Java EE csak a JMS támogatását írja elő, habár ez más üzenetküldési protokollokat is támogathat. Ezek a protokollok lehetnek szinkronok és aszinkronok is. A fő különbség nem is ebben rejlik, hanem a metódushívás és az üzenetküldés közötti különbségben.

Példák:

  • Több csomópontnak kell értesítést küldeni a beállításokról úgy, hogy az üzenetküldőnek ne kelljen ismernie a címzetteket, a helyüket vagy a számukat. A témára egy erre feliratkozott MDB küldi az üzeneteket.
  • Egy szálkészletnek kell elvégzendő feladatokat közvetíteni. Mindegy, hogy az adott feladatot melyik szál végzi el a készletből. Az üzenetvezérelt bean egy üzenetsorra küldi az információt. Az üzenetsor biztosítja, hogy egy feladatot ne végezzenek el többen.

Entitás bean (Entity bean)[szerkesztés | forrásszöveg szerkesztése]

Az entitás bean szerveroldali Java-EE komponens, amely adatbázisban nyilvántartott adatokat képvisel, így van neki azonosító kulcsa. A fenti típusoktól eltérően távoli referenciáival együtt túléli a konténer összeomlását is. Az EJB 2.0-ban definiálták őket, és az EJB 3.0 óta elavultnak számítanak, és a JPA API helyettesíti őket.

Ebből is két fajta van: BMP (Bean Management Beans) és CMP (Container Managed Beans). Míg az első esetben a fejlesztőnek magának kell gondoskodnia a perzisztencia megoldásáról betartva az EJB szabványt, addig a második esetben a perzisztencia vezérlést teljes egészében a konténerre bízható, és ténylegesen csak az üzleti logika megvalósítására lehet összpontosítani.

Működés[szerkesztés | forrásszöveg szerkesztése]

A rendszer az EJB-ket konténerekbe telepíti (deployolja), amelyek rendszerint alkalmazászerveren belül futnak. A specifikáció leírja, hogyan kapcsolódik az EJB a konténerhez, és a kliens kód hogy működik együtt a konténerrel és az EJB-vel. Az EJB-k megvalósításához szükséges eszközök a javax.ejb csomagban találhatók. A javax.ejb.spi a szerver kiszolgáló eszközöket tartalmazza, amelyeket a konténerek használnak.

A kliensek nem példányosítják közvetlenül az EJB-ket, hanem kérnek a konténertől egy példányt. A konténer egy referenciát ad vissza, ami nem magára az EJB példányra hivatkozik, hanem egy proxy objektumra. Ez vagy a helyi vagy a távoli üzleti interfészt valósítja meg a kliens kérése szerint, vagy dinamikusan implementálja az EJB altípusát. Mindemiatt a proxy típusa olyan, hogy megfelel a kliens által elvárt interfésznek. Azt mondjuk, hogy a kliensnek van egy nézete az EJB-ről, ami lehet távoli, helyi vagy nem interfész nézet aszerint, hogy melyik interfészt, vagy magát a beant mutatja-e.

Ez a proxy lehetőséget ad a konténernek, hogy különböző szolgáltatásokat nyújtson rajta keresztül, így tranzakciókezelést, távoli eljáráshívást, injektálást, adatvédelmet. Egyes szolgáltatások az aspektusorientált programozás szerint szerveződnek, mint például az interceptorok.

Például a kliens meghívja a proxy egy metódusát. Ennek hatására előbb elindul egy tranzakció a szerveren, majd az EJB üzleti metódusa is elindul. Miután a metódus visszatért, a proxy fejezi be a tranzakciót, és visszaadja a vezérlést a kliensnek.

Tranzakciók[szerkesztés | forrásszöveg szerkesztése]

Az EJB konténereknek támogatniuk kell mind a konténermenedzselt KATI (angolul: ACID) tranzakciókat, mind a bean menedzselt tranzakciókat.[13]

A KATI rövidítés a konzisztencia, atomicitás, tartósság és izoláltság szavakat foglalja magába, amelyek a tranzakciók jellemzői. 

Alapértelmezetten a konténer kezeli a tranzakciókat (CMT), így ezt nem kell beállítani. A bean ezt segítheti különféle annotációkkal, amelyek leírják például, hogy melyik művelet milyen lockot igényel. Vannak annotációk, amelyek megváltoztatják a tranzakcionális viselkedést, vagy kikapcsolják a tranzakciókat. A metódusok egyenként is megjelölhetők. Ez a viselkedés magában foglalja, hogy hogyan reagáljanak arra, hogy a kliens tranzakciót kezdeményezett, vagy tranzakción kívül hívták meg.[14][15] Az interceptorok indíthatnak vagy leállíthatnak tranzakciókat, tehát nem mindig a kliens viselkedése a meghatározó.

Viselkedési típusok a tranzakciós környezettel szemben
Típus Leírás
MANDATORY Ha nincs tranzakció, akkor hibát jelez, különben csatlakozik a tranzakcióhoz.
REQUIRED Ha nincs tranzakció, akkor újat indít. Ha van, akkor csatlakozik hozzá. Ez az alapértelmezett viselkedés.
REQUIRES_NEW Ha van tranzakció, akkor azt félreteszi. Minden esetben új tranzakciót indít.
SUPPORTS Ha van tranzakció, akkor csatlakozik hozzá, különben tranzakción kívül fut le.
NOT_SUPPORTED Ha van tranzakció, akkor azt félreteszi, és tranzakción kívül fut le.
NEVER Ha van tranzakció, akkor kivételt dob. Sosem indít tranzakciót.

Jegyzetek[szerkesztés | forrásszöveg szerkesztése]

  1. Enterprise JavaBeans Technology. (Hozzáférés: 2010. február 5.)
  2. J2EE Design and Development, © 2002 Wrox Press Ltd., p. 5.
  3. Types of Enterprise Beans. (Hozzáférés: 2010. február 5.)
  4. State Management Modes. (Hozzáférés: 2010. február 5.)
  5. JSR 318, 4.7, http://jcp.org/en/jsr/detail?id=318
  6. ^ a b JSR 318, 4.10.3, http://jcp.org/en/jsr/detail?id=318
  7. JSR 318, 4.3.14, http://jcp.org/en/jsr/detail?id=318
  8. JSR 318, 4.6, http://jcp.org/en/jsr/detail?id=318
  9. JSR 318, 4.3.14, 21.4.2, http://jcp.org/en/jsr/detail?id=318
  10. http://blogs.sun.com/enterprisetechtips/entry/extended_persistence_context_in_stateful
  11. JSR 318, 4.8, http://jcp.org/en/jsr/detail?id=318
  12. Singleton EJB. Openejb.apache.org. (Hozzáférés: 2012. június 17.)
  13. JSR 318, Chapter 13, http://jcp.org/en/jsr/detail?id=318
  14. JSR 318, 13.6.2, http://jcp.org/en/jsr/detail?id=318
  15. Transaction Annotations. Openejb.apache.org. (Hozzáférés: 2012. június 17.)