Spring Bean vs. EJB - A jellemzők összehasonlítása

1. Áttekintés

Az évek során a Java ökoszisztémája óriási mértékben fejlődött és nőtt. Ez idő alatt az Enterprise Java Beans és a Spring két olyan technológia, amelyek nemcsak versenyeztek, hanem szimbiotikusan is tanultak egymástól.

Ebben az oktatóanyagban megnézzük történelmüket és különbségeiket. Természetesen látni fogunk néhány kód példát az EJB-re és annak megfelelőire a tavaszi világban.

2. A technológiák rövid története

Először is vessünk egy gyors pillantást e két technológia történetére és azok folyamatos fejlődésére az évek során.

2.1. Enterprise Java Beans

Az EJB specifikáció a Java EE (vagy J2EE, ma Jakarta EE néven ismert) specifikáció részhalmaza. Első verziója 1999-ben jelent meg, és ez az egyik első technológia, amelyet a szerveroldali vállalati alkalmazások fejlesztésének megkönnyítésére fejlesztettek ki a Java-ban.

Felhúzta a Java fejlesztők terhét az egyidejűség, biztonság, kitartás, tranzakciók feldolgozása, és több. A specifikáció ezeket és más általános vállalati problémákat adta át a megvalósító alkalmazáskiszolgálók tárolóinak, amelyek zökkenőmentesen kezelték őket. Az EJB-k használata azonban kissé nehézkes volt a szükséges konfiguráció mennyisége miatt. Sőt, ez a teljesítmény szűk keresztmetszetének bizonyult.

De most, az annotációk feltalálásával és a Spring erős versenyével az EJB-k a legújabb 3.2-es verziójukban sokkal egyszerűbben használhatók, mint a debütáló verziójuk. Az Enterprise Java Beans napjainkban nagyrészt kölcsönöz a Spring függőség-injektálásából és a POJO-k használatából.

2.2. Tavaszi

Míg az EJB-k (és általában a Java EE) a Java közösség megelégedéséért küzdöttek, a Spring Framework friss levegőként érkezett. Első mérföldkő kiadása 2004-ben jelent meg, és alternatívát kínált az EJB modellhez és nehézsúlyú konténereihez.

Hála tavasznak, A Java vállalati alkalmazások most már könnyebb IOC konténereken futtathatók. Ráadásul függőségi inverziót, AOP-t és hibernált támogatást is kínál számtalan egyéb hasznos szolgáltatás között. A Java közösség óriási támogatásával a Spring mára exponenciálisan növekedett, és teljes Java / JEE alkalmazás keretrendszernek nevezhető.

Legújabb avatárjában a Spring 5.0 még a reaktív programozási modellt is támogatja. Egy másik ág, a Spring Boot egy teljes játékváltó beágyazott szerverekkel és automatikus konfigurációkkal.

3. Előszó a Feature Comparison-tól

Mielőtt a kódmintákkal összehasonlítanánk a funkciókat, állítsunk össze néhány alapot.

3.1. Alapvető különbség a kettő között

Először is, az alapvető és látszólagos különbség az Az EJB egy specifikáció, míg a tavasz egy teljes keret.

A specifikációt számos alkalmazásszerver hajtja végre, például a GlassFish, az IBM WebSphere és a JBoss / WildFly. Ez azt jelenti, hogy az EJB modell alkalmazásunk háttér-fejlesztéséhez való választása nem elegendő. Azt is ki kell választanunk, hogy melyik alkalmazásszervert használjuk.

Elméletileg az Enterprise Java Beans hordozható az alkalmazásszervereken, bár mindig fennáll annak az előfeltétele, hogy ne használjunk gyártóspecifikus bővítményeket, ha az interoperabilitást opcióként kívánjuk megtartani.

Második, A tavasz, mivel a technológia szélesebb kínálatát tekintve közelebb áll a Java EE-hez, mint az EJB. Míg az EJB-k csak a háttérprogram műveleteket adják meg, a Spring, mint a Java EE, támogatja a felhasználói felület fejlesztését, a RESTful API-kat és a reaktív programozást, hogy csak néhányat említsünk.

3.2. Hasznos információ

A következő szakaszokban láthatjuk a két technológia összehasonlítását néhány gyakorlati példával. Mivel az EJB jellemzői a jóval nagyobb tavaszi ökoszisztéma részhalmaza, áttekintjük a típusaikat, és megnézzük a megfelelő tavaszi megfelelőiket.

A példák jobb megértése érdekében először fontolja meg a Java EE Session Bean, Message Driven Beans, Spring Bean és Spring Bean Annotations felolvasását.

Az OpenJB-t fogjuk beágyazott tárolónként használni az EJB-minták futtatásához. A tavaszi példák nagy részének futtatásához elegendő a NOB konténere; a tavaszi JMS-hez szükségünk lesz egy beágyazott ApacheMQ közvetítőre.

Minden mintánk teszteléséhez a JUnit programot fogjuk használni.

4. Singleton EJB == Tavasz Összetevő

Néha szükségünk van a tárolóra, hogy csak egy babszemet hozzunk létre. Tegyük fel például, hogy babra van szükségünk, hogy megszámoljuk a webalkalmazásunk látogatóinak számát. Ezt a babot csak egyszer kell létrehozni az alkalmazás indításakor.

Nézzük meg, hogyan lehet ezt elérni a Singleton Session EJB és a Spring segítségével Összetevő.

4.1. Singleton EJB példa

Először szükségünk lesz egy interfészre annak megadásához, hogy az EJB képes-e távoli kezelésre:

@ Távoli nyilvános felület CounterEJBRemote {int count (); String getName (); void setName (karakterlánc neve); }

A következő lépés az definiáljon egy megvalósítási osztályt az annotációval javax.ejb.Singleton, és brácsa! A szinglik készen áll:

@Singleton nyilvános osztály CounterEJB végrehajtja CounterEJBRemote {private int count = 1; privát karakterlánc neve; public int count () {return count ++; } // getter és setter for name} 

De mielőtt tesztelhetnénk a szingletont (vagy bármely más EJB kódmintát), inicializálnunk kell a ejbContainer és megkapja a kontextus:

@BeforeClass public void initializeContext () dobja a NamingException {ejbContainer = EJBContainer.createEJBContainer (); context = ejbContainer.getContext (); context.bind ("inject", ez); } 

Most nézzük meg a tesztet:

@Test public void givenSingletonBean_whenCounterInvoked_thenCountIsIncremented () dob NamingException {int count = 0; CounterEJBRemote firstCounter = (CounterEJBRemote) context.lookup ("java: globális / ejb-bab / CounterEJB"); firstCounter.setName ("első"); mert (int i = 0; i <10; i ++) {count = firstCounter.count (); } assertEquals (10, szám); assertEquals ("first", firstCounter.getName ()); CounterEJBRemote secondCounter = (CounterEJBRemote) context.lookup ("java: globális / ejb-bab / CounterEJB"); int szám2 = 0; mert (int i = 0; i <10; i ++) {count2 = secondCounter.count (); } assertEquals (20, count2); assertEquals ("first", secondCounter.getName ()); } 

Néhány megjegyzendő dolog a fenti példában:

  • A JNDI keresést használjuk számlálóEJB a tartályból
  • count2 felveszi a lényegről számol itt hagyta a szinglit, és összeadja 20
  • secondCounter megtartja a beállított nevet firstCounter

Az utolsó két pont a szinglik jelentőségét mutatja be. Mivel ugyanazt a babpéldányt használjuk minden egyes kereséskor, a teljes szám 20, az egyikre beállított érték ugyanaz marad a másiknál.

4.2. Példa Singleton tavaszi babra

Ugyanez a funkcionalitás érhető el a rugós alkatrészek használatával.

Itt nem kell semmilyen interfészt bevezetnünk. Ehelyett hozzáadjuk a @Összetevő kommentár:

@Component public class CounterBean {// ugyanaz a tartalom, mint az EJB-ben}

Valójában az alkatrészek alapértelmezés szerint tavasszal egyedülállóak.

Be kell állítanunk a Spring-et is az alkatrészek keresésére:

@Configuration @ComponentScan (basePackages = "com.baeldung.ejbspringcomparison.spring") public class ApplicationConfig {} 

Az EJB kontextus inicializálásához hasonlóan most beállítjuk a tavaszi kontextust:

@BeforeClass public static void init () {context = new AnnotationConfigApplicationContext (ApplicationConfig.class); } 

Most nézzük meg a mi Összetevő működés közben:

@Test public void whenCounterInvoked_thenCountIsIncremented () dobja a NamingException {CounterBean firstCounter = context.getBean (CounterBean.class); firstCounter.setName ("első"); int szám = 0; mert (int i = 0; i <10; i ++) {count = firstCounter.count (); } assertEquals (10, szám); assertEquals ("first", firstCounter.getName ()); CounterBean secondCounter = context.getBean (CounterBean.class); int szám2 = 0; mert (int i = 0; i <10; i ++) {count2 = secondCounter.count (); } assertEquals (20, count2); assertEquals ("first", secondCounter.getName ()); } 

Mint láthatjuk, az EJB-kkel szemben az egyetlen különbség az, hogy a JNDI keresés helyett hogyan kapjuk meg a babot a tavaszi konténer kontextusából.

5. Állapotú EJB == Tavasz Összetevő val vel prototípus Hatály

Időnként mondjuk, amikor bevásárlókocsit építünk, szükségünk van a babunkra, hogy emlékezzen az állapotára, miközben a módszerhívások között oda-vissza haladunk.

Ebben az esetben szükségünk van a tárolónkra, hogy minden meghíváshoz külön babot hozzunk létre, és mentse az állapotot. Nézzük meg, hogyan érhető el ez a kérdéses technológiáinkkal.

5.1. Állapotú EJB példa

Hasonlóan a szingulett EJB mintánkhoz, szükségünk van a javax.ejb.Távoli felület és annak megvalósítása. Csak ezúttal a javax.ejb.Stateful:

@Stateful public class ShoppingCartEJB hajtja végre a ShoppingCartEJBRemote {private String name; privát List shoppingCart; public void addItem (String item) {shoppingCart.add (item); } // kivitelező, mérőeszközök és beállítók}

Írjunk egy egyszerű tesztet az a beállítására név és tegyen elemeket a bathingCart. Ellenőrizzük a méretét és a nevét:

@Test public void givenStatefulBean_whenBathingCartWithThreeItemsAdded_thenItemsSizeIsThree () dob NamingException {ShoppingCartEJBRemote bathingCart = (ShoppingCartEJBRemote) context.lookup ("java: global / ejb-beans / Shopping"; bathingCart.setName ("bathingCart"); bathingCart.addItem ("szappan"); bathingCart.addItem ("sampon"); bathingCart.addItem ("olaj"); assertEquals (3, bathingCart.getItems (). size ()); assertEquals ("bathingCart", bathingCart.getName ()); } 

Most annak bemutatásához, hogy a bab valóban fenntartja az állapotot az összes példányon, adjunk hozzá egy másik shoppingCartEJB-t ehhez a teszthez:

ShoppingCartEJBRemote fruitCart = (ShoppingCartEJBRemote) context.lookup ("java: globális / ejb-bab / ShoppingCartEJB"); fruitCart.addItem ("alma"); fruitCart.addItem ("narancs"); assertEquals (2, fruitCart.getItems (). size ()); assertNull (fruitCart.getName ()); 

Itt nem állítottuk be a név és ezért értéke semmis volt. Emlékezzünk vissza a szingulett tesztből, hogy az egyik példányban beállított név megmaradt egy másikban. Ez azt bizonyítja, hogy különváltunk ShoppingCartEJB a babkészletből származó példányok különböző példányállapotokkal.

5.2. Államszerű tavaszi babpélda

Ahhoz, hogy ugyanazt a hatást érjük el tavasszal, szükségünk van a Összetevő prototípus hatókörrel:

@Component @Scope (value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class ShoppingCartBean {// ugyanazon tartalom, mint az EJB-ben} 

Ennyi, csak a kommentárok különböznek - a kód többi része ugyanaz marad.

Az Stateful babunk tesztelésére ugyanazt a tesztet használhatjuk, amelyet az EJB-knél leírtak. Az egyetlen különbség megint az, hogy hogyan kapjuk meg a babot a tartályból:

ShoppingCartBean bathingCart = context.getBean (ShoppingCartBean.class); 

6. Hontalan EJB! = Bármi tavasszal

Néha, például egy keresési API-ban, nem érdekel sem a bab példányállapota, sem az, ha szingulett. Szükségünk van a keresés eredményeire, amelyek minden babpéldányból származhatnak mindazokra, akiket érdekel.

6.1. Hontalan EJB példa

Ilyen esetekben az EJB-nek van hontalan változata. A tároló egy babkészletet tart fenn, és bármelyikük visszatér a hívási módszerhez.

Meghatározásunk megegyezik más EJB típusokkal, távoli interfésszel és megvalósítással javax.ejb.állapot nélküli kommentár:

@ Állapot nélküli nyilvános osztályban a FinderEJB megvalósítja a FinderEJBRemote {privát Térkép ábécét; public FinderEJB () {ábécé = új HashMap (); alphabet.put ("A", "Apple"); // adjon hozzá további értékeket a térképen itt} public String search (String keyword) {return alphabet.get (keyword); }} 

Adjunk hozzá még egy egyszerű tesztet, hogy lássuk ezt a műveletet:

@Test public void givenStatelessBean_whenSearchForA_thenApple () dobja a NamingException {assertEquals ("Apple", alphabetFinder.search ("A")); } 

A fenti példában alphabetFinder mezőbe injektálják a tesztosztályban az annotáció segítségével javax.ejb.EJB:

@EJB privát FinderEJBRemote alphabetFinder; 

A Hontalan EJB-k mögött álló központi gondolat az, hogy növelje a teljesítményt egy példányos hasonló bab-készlet birtokában.

Azonban, Spring nem vállalja fel ezt a filozófiát, és csak hontalanként kínálja a szingliket.

7. Üzenettel vezérelt bab == Tavaszi JMS

Az összes eddig tárgyalt EJB munkamag bab volt. Egy másik fajta az üzenet által vezérelt. Ahogy a neve is sugallja, ezeket általában két rendszer közötti aszinkron kommunikációra használják.

7.1. MDB példa

Üzenet-vezérelt Enterprise Java Bean létrehozásához végre kell hajtanunk a javax.jms.MessageListener interfész meghatározza annak onMessage metódust, és jegyezze fel az osztályt javax.ejb.MessageDriven:

@MessageDriven (activationConfig = {@ActivationConfigProperty (tulajdonságNév = "cél", tulajdonságValue = "myQueue"), @ActivationConfigProperty (tulajdonságNév = "céltípus", tulajdonságValue = "javax.jms.Queue")}) nyilvános osztály RecieverLD Erőforrás privát ConnectionFactory connectionFactory; @Resource (név = "ackQueue") privát várólista ackQueue; public void onMessage (Üzenet) {try {TextMessage textMessage = (TextMessage) üzenet; String producerPing = textMessage.getText (); if (producerPing.equals ("marco")) {nyugtázza ("póló"); }} catch (JMSException e) {dobja az új IllegalStateException (e) -t; }}} 

Vegye figyelembe, hogy az MDB-hez is konfigurálunk néhányat:

      • destinationType mint Sor
      • myQueue mint a rendeltetési hely sor neve, amelyre babunk hallgat

Ebben a példában a mi a vevő nyugtázást is létrehoz, és ebben az értelemben önmagában küldő. Üzenetet küld egy másik hívott sornak ackQueue.

Most lássuk ezt egy teszt segítségével:

@Test public void givenMDB_whenMessageSent_thenAcknowledgementReceived () dobja az InterruptedException, JMSException, NamingException {Connection connection = connectionFactory.createConnection (); kapcsolat.indítás (); Munkamenet = connection.createSession (false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer (myQueue); producer.send (session.createTextMessage ("marco")); MessageConsumer response = session.createConsumer (ackQueue); assertEquals ("polo", (((TextMessage) response.receive (1000)). getText ()); } 

Itt üzenetet küldtünk a myQueue, amelyet a miénk fogadott @MessageDriven megjegyzéssel POJO. Ez a POJO ezután nyugtázást küldött, és tesztünk a válaszként megkapta a választ MessageConsumer.

7.2. Tavaszi JMS példa

Nos, itt az ideje, hogy ugyanezt tegyük a Spring használatával!

Először hozzá kell adnunk egy kis konfigurációt erre a célra. Meg kell jegyeznünk a ApplicationConfig osztály az elõtõl együtt @EnableJms és adj hozzá néhány babot a beállításhoz JmsListenerContainerFactory és JmsTemplate:

@EnableJms public class ApplicationConfig {@Bean public DefaultJmsListenerContainerFactory jmsListenerContainerFactory () {DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory (); gyár.setConnectionFactory (connectionFactory ()); visszatérő gyár; } @Bean public ConnectionFactory connectionFactory () {return new ActiveMQConnectionFactory ("tcp: // localhost: 61616"); } @Bean public JmsTemplate jmsTemplate () {JmsTemplate template = új JmsTemplate (connectionFactory ()); template.setConnectionFactory (connectionFactory ()); visszatérési sablon; }} 

Ezután szükségünk van egy Termelő - egy egyszerű tavasz Összetevő - ezzel üzeneteket fog küldeni myQueue és megkapja a nyugtát ackQueue:

@ Component public class Producer {@Autowired private JmsTemplate jmsTemplate; public void sendMessageToDefaultDestination (utolsó karakterlánc üzenet) {jmsTemplate.convertAndSend ("myQueue", üzenet); } public String ReceiveAck () {return (String) jmsTemplate.receiveAndConvert ("ackQueue"); }} 

Aztán van egy VevőÖsszetevő módszerrel kommentált módszerrel @JmsListener hogy aszinkron módon fogadjon üzeneteket myQueue:

@ Component public class Receiver {@Autowired private JmsTemplate jmsTemplate; @JmsListener (cél = "myQueue") public void fogadMessage (Karakterlánc msg) {sendAck (); } private void sendAck () {jmsTemplate.convertAndSend ("ackQueue", "polo"); }} 

Feladóként is működik az üzenet átvételének megerősítéséhez a következő címen: ackQueue.

Gyakorlatunk szerint ellenőrizzük ezt egy teszttel:

@Test public void givenJMSBean_whenMessageSent_thenAcknowledgementReceived () dobja a NamingException {Producer producer = context.getBean (Producer.class); producer.sendMessageToDefaultDestination ("marco"); assertEquals ("polo", producer.receiveAck ()); } 

Ebben a tesztben elküldtük marco nak nek myQueue és megkapta póló mint nyugtázást a ackQueue, ugyanaz, mint amit az EJB-vel tettünk.

Itt megjegyzendő egy dolog A tavaszi JMS szinkron és aszinkron módon is képes üzeneteket küldeni / fogadni.

8. Következtetés

Ebben az oktatóanyagban láttuk a a Spring és az Enterprise Java Beans egy-egy összehasonlítása. Megértettük történetüket és alapvető különbségeiket.

Ezután egyszerű példákkal foglalkoztunk, hogy bemutassuk a tavaszi bab és az EJB összehasonlítását. Szükségtelen mondani, pusztán a felület felkarolása, mire képesek a technológiák, és még sok minden további vizsgálandó.

Ezenkívül ezek egymással versengő technológiák lehetnek, de ez nem jelenti azt, hogy nem létezhetnek együtt. Könnyen integrálhatjuk az EJB-ket a tavaszi keretbe.

Mint mindig, a forráskód is elérhető a GitHubon.


$config[zx-auto] not found$config[zx-overlay] not found