שעועית אביב נגד EJB - השוואה בין תכונות

1. סקירה כללית

במהלך השנים, המערכת האקולוגית של ג'אווה התפתחה וגדלה מאוד. במהלך תקופה זו, Enterprise Java Beans ו- Spring הן שתי טכנולוגיות שלא רק התחרו אלא למדו זו מזו באופן סימביוטי.

במדריך זה, אנו נסתכל על ההיסטוריה וההבדלים ביניהם. כמובן שנראה כמה דוגמאות קוד של EJB ושווי המקבילות שלהן בעולם האביב.

2. היסטוריה קצרה של הטכנולוגיות

ראשית, בואו נסתכל במהירות על ההיסטוריה של שתי הטכנולוגיות הללו וכיצד הן התפתחו בהתמדה לאורך השנים.

2.1. שעועית ג'אווה ארגונית

מפרט EJB הוא קבוצת משנה של מפרט Java EE (או J2EE, המכונה כיום ג'קרטה EE).. הגרסה הראשונה שלה יצאה בשנת 1999, והיא הייתה אחת הטכנולוגיות הראשונות שנועדו להקל על פיתוח יישומים ארגוניים בצד השרת בג'אווה.

זה כתף את הנטל של מפתחי Java במקביל, אבטחה, התמדה ועיבוד עסקאות, ועוד. המפרט העביר חששות ארגוניים נפוצים אחרים ואחרים למיכלים של שרתי היישומים המיישמים, שטיפלו בהם בצורה חלקה. עם זאת, השימוש ב- EJB כפי שהיה היה מעט מסורבל בגלל כמות התצורה הנדרשת. יתר על כן, זה התגלה כצוואר בקבוק ביצועים.

אבל עכשיו, עם המצאת ההערות והתחרות הקשה של אביב, EJBs בגרסת 3.2 האחרונה שלהם הם הרבה יותר פשוטים לשימוש מגרסת הבכורה שלהם. שעועית Java של ימינו לווים בכבדות מהזרקת התלות של אביב ומשימוש ב- POJO.

2.2. אביב

בעוד EJBs (ו- Java EE בכלל) נאבקו לספק את קהילת ג'אווה, Spring Framework הגיעה כמו משב אוויר צח. מהדורת הדרך הראשונה שלה יצאה בשנת 2004 והציעה אלטרנטיבה לדגם EJB ולמכולות הכבדות שלו.

תודה לאביב, כעת ניתן להריץ יישומי ארגונים של Java על מכלי IOC קלים יותר. יתר על כן, היא הציעה גם היפוך תלות, AOP ותמיכה במצב שינה בין מספר עצום של תכונות שימושיות אחרות. עם תמיכה אדירה מקהילת ג'אווה, אביב גדל כעת באופן אקספוננציאלי וניתן לכנותו כמסגרת יישומי Java / JEE מלאה.

באווטאר האחרון שלה, אביב 5.0 תומך אפילו במודל התכנות תגובתי. שלוחה נוספת, Spring Boot, היא מחליף משחקים מלא עם שרתים ותצורות אוטומטיות.

3. פרלוד להשוואת התכונות

לפני שנקפוץ להשוואת התכונות עם דוגמאות קוד, בואו נקבע כמה יסודות.

3.1. ההבדל הבסיסי בין השניים

ראשית, ההבדל המהותי והנראה הוא בכך EJB הוא מפרט, ואילו האביב הוא מסגרת שלמה.

המפרט מיושם על ידי שרתי יישומים רבים כמו GlassFish, IBM WebSphere ו- JBoss / WildFly. המשמעות היא שלא די בבחירתנו להשתמש במודל EJB לצורך פיתוח backend של היישום שלנו. עלינו גם לבחור באיזה שרת יישומים להשתמש.

תיאורטית, שעועיות Java Enterprise הן ניידות על פני שרתי אפליקציות, אם כי תמיד יש את התנאי שלא נשתמש בתוספים ספציפיים לספקים אם יש לשמור על יכולת פעולה הדדית כאופציה.

שְׁנִיָה, אביב כטכנולוגיה קרוב יותר ל- Java EE מאשר ל- EJB מבחינת תיק ההיצע הרחב שלה. בעוד ש- EJB מציינים רק פעולות backend, ל- Spring, כמו Java EE, יש גם תמיכה בפיתוח ממשק משתמש, ממשקי API של RESTful ותכנות תגובתי עד כמה שם.

3.2. מידע שימושי

בחלקים הבאים נראה את ההשוואה בין שתי הטכנולוגיות עם כמה דוגמאות מעשיות. מכיוון שתכונות EJB הן קבוצת משנה של המערכת האקולוגית הרבה יותר גדולה באביב, נלך לפי הסוגים שלהן ונראה את מקבילות האביב המקבילות להן.

כדי להבין בצורה הטובה ביותר את הדוגמאות, שקול קודם לקרוא על Java EE Session Beans, שעועית מונעת הודעה, Spring Bean ו- Spring Bean.

נשתמש ב- OpenJB כמיכל המשובץ שלנו להפעלת דגימות ה- EJB. להפעלת רוב דוגמאות האביב, מיכל ה- IOC שלו יספיק; עבור Spring JMS, נצטרך מתווך ApacheMQ משובץ.

כדי לבדוק את כל הדגימות שלנו, נשתמש ב- JUnit.

4. סינגלטון EJB == אביב רְכִיב

לפעמים אנו זקוקים למכולה כדי ליצור רק מופע יחיד של שעועית. לדוגמה, נניח שאנחנו צריכים שעועית כדי לספור את מספר המבקרים ביישום האינטרנט שלנו. שעועית זו צריכה להיווצר רק פעם אחת במהלך הפעלת היישום.

בואו נראה איך להשיג זאת באמצעות מושב סינגלטון EJB ומעיין רְכִיב.

4.1. דוגמה ל- Singleton EJB

ראשית נצטרך ממשק כדי לציין של- EJB שלנו יש את היכולת לטפל מרחוק:

ממשק ציבורי @ Remote CounterEJBRemote {int count (); מחרוזת getName (); void setName (שם מחרוזת); }

השלב הבא הוא ל הגדר מחלקת יישום עם ההערה javax.ejb.Singletonויולה! הסינגלטון שלנו מוכן:

@Singleton CounterEJB בכיתה ציבורית מיישמת CounterEJBRemote {int int count = 1; שם מחרוזת פרטי; ספירת int public () {ספירת החזר ++; } // גטר וקובע שם} 

אך לפני שנוכל לבדוק את הסינגלטון (או כל דוגמת קוד EJB אחרת), עלינו לאתחל את ה- ejb מיכל ולקבל את הֶקשֵׁר:

@BeforeClass חלל ציבורי initializeContext () זורק NamingException {ejbContainer = EJBContainer.createEJBContainer (); context = ejbContainer.getContext (); context.bind ("להזריק", זה); } 

עכשיו בואו נסתכל על המבחן:

@Test הציבור בטל givenSingletonBean_whenCounterInvoked_thenCountIsIncremented () זורק NamingException {int count = 0; CounterEJBRemote firstCounter = (CounterEJBRemote) context.lookup ("java: global / ejb-beans / CounterEJB"); firstCounter.setName ("ראשון"); עבור (int i = 0; i <10; i ++) {count = firstCounter.count (); } assertEquals (10, count); assertEquals ("first", firstCounter.getName ()); CounterEJBRemote secondCounter = (CounterEJBRemote) context.lookup ("java: global / ejb-beans / CounterEJB"); int count2 = 0; עבור (int i = 0; i <10; i ++) {count2 = secondCounter.count (); } assertEquals (20, count2); assertEquals ("first", secondCounter.getName ()); } 

כמה דברים שיש לציין בדוגמה שלעיל:

  • אנו משתמשים בחיפוש JNDI כדי להשיג counterEJB מהמיכל
  • ספירה 2 מרים מהנקודה לספור השאיר את היחיד ב, ומוסיף עד 20
  • מונה שני שומר על השם שאליו הגדרנו firstCounter

שתי הנקודות האחרונות מדגימות את המשמעות של יחיד. מכיוון שמשתמשים באותה מופע שעועית בכל פעם שהוא נבדק, הספירה הכוללת היא 20 והערך שנקבע עבור אחד נשאר זהה עבור השני.

4.2. דוגמא של שעועית אביב סינגלטון

ניתן להשיג את אותה פונקציונליות באמצעות רכיבי Spring.

איננו צריכים ליישם כאן ממשק כלשהו. במקום זאת, נוסיף את @רְכִיב ביאור:

@CounterBean מחלקה ציבורית @Component {// אותו תוכן כמו ב- EJB}

למעשה, רכיבים הם יחידים כברירת מחדל באביב.

עלינו גם להגדיר את האביב כדי לחפש רכיבים:

@Configuration @ComponentScan (basePackages = "com.baeldung.ejbspringcomparison.spring") מחלקה ציבורית ApplicationConfig {} 

בדומה לאופן שאותחנו את הקשר EJB, כעת נקבע את הקשר האביב:

@BeforeClass init סטטי ציבור ריק () {context = חדש AnnotationConfigApplicationContext (ApplicationConfig.class); } 

עכשיו בואו נראה את שלנו רְכִיב בִּפְעוּלָה:

@ מבחן ציבורי בטל כאשר CounterInvoked_thenCountIsIncremented () זורק NamingException {CounterBean firstCounter = context.getBean (CounterBean.class); firstCounter.setName ("ראשון"); ספירת int = 0; עבור (int i = 0; i <10; i ++) {count = firstCounter.count (); } assertEquals (10, count); assertEquals ("first", firstCounter.getName ()); CounterBean secondCounter = context.getBean (CounterBean.class); int count2 = 0; עבור (int i = 0; i <10; i ++) {count2 = secondCounter.count (); } assertEquals (20, count2); assertEquals ("first", secondCounter.getName ()); } 

כפי שאנו רואים, ההבדל היחיד ביחס ל- EJBs הוא כיצד אנו מקבלים את השעועית מההקשר של מיכל האביב, במקום בדיקת JNDI.

5. EJB אמיתי == אביב רְכִיב עם אב טיפוס תְחוּם

לפעמים אמור כשאנחנו בונים עגלת קניות, אנו זקוקים לשעועית שלנו כדי לזכור את מצבה תוך כדי הלוך ושוב בין שיחות השיטה.

במקרה זה, אנו זקוקים למכולה שלנו כדי ליצור שעועית נפרדת לכל קריאה ולהציל את המדינה. בואו נראה כיצד ניתן להשיג זאת בעזרת הטכנולוגיות המדוברות שלנו.

5.1. דוגמא למדינת EJB

בדומה לדוגמת EJB של יחיד, אנו זקוקים ל- מרחוק ממשק ויישומו. רק שהפעם, הערותיה עם javax.ejb.סטטיווי:

מחלקה ציבורית סטטיסטית ShoppingCartEJB מיישמת ShoppingCartEJBRemote {שם פרטי מחרוזת; פרטי רשימת shoppingCart; addItem public void (פריט מחרוזת) {shoppingCart.add (פריט); } // קונסטרוקטור, גטרים וקובעים}

בוא נכתוב מבחן פשוט לקביעת a שֵׁם ולהוסיף פריטים לא bathingCart. נבדוק את גודלו ונוודא את השם:

@Test הציבורי בטל שניתן StatatefulBean_whenBathingCartWithThreeItemsAdded_thenItemsSizeIsThree () זורק NamingException {ShoppingCartEJBRemote bathingCart = (ShoppingCartEJBRemote) context.lookup ("java: global / ejb-beans / ShoppingCartEJB) bathingCart.setName ("bathingCart"); bathingCart.addItem ("סבון"); bathingCart.addItem ("שמפו"); bathingCart.addItem ("שמן"); assertEquals (3, bathingCart.getItems (). size ()); assertEquals ("bathingCart", bathingCart.getName ()); } 

עכשיו, כדי להוכיח שהשעועית באמת שומרת על מצב בכל מקרים, בואו נוסיף עוד shoppingCartEJB למבחן זה:

ShoppingCartEJBRemote fruitCart = (ShoppingCartEJBRemote) context.lookup ("java: global / ejb-beans / ShoppingCartEJB"); fruitCart.addItem ("תפוחים"); fruitCart.addItem ("תפוזים"); assertEquals (2, fruitCart.getItems (). size ()); assertNull (fruitCart.getName ()); 

כאן לא הגדרנו את שֵׁם ומכאן שערכו היה אפס. נזכיר ממבחן הסינגלטון, שהשם שנקבע במקרה אחד נשמר במקרה אחר. זה ממחיש שנפרדנו ShoppingCartEJB מקרים מבריכת השעועית עם מצבי מופע שונים.

5.2. דוגמה לשעועית אביבית סטטיסטית

כדי לקבל את אותו האפקט עם אביב, אנו זקוקים ל- רְכִיב עם היקף אב-טיפוס:

@Component @Scope (value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) מחלקה ציבורית ShoppingCartBean {// אותו תוכן כמו ב- EJB} 

זהו, רק ההערות שונות - שאר הקוד נשאר זהה.

כדי לבדוק את השעועית הסטטית שלנו, אנו יכולים להשתמש באותה בדיקה כמתואר עבור EJB. ההבדל היחיד הוא שוב כיצד אנו מקבלים את השעועית מהמיכל:

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

6. EJB חסר מדינה! = כל דבר באביב

לפעמים, למשל בממשק API לחיפוש, לא אכפת לנו ממצב המופע של שעועית ולא אם זה יחיד. אנחנו רק צריכים את תוצאות החיפוש שלנו, שעשויות להגיע מכל מופע שעועית לכל מה שאכפת לנו.

6.1. דוגמא ל- EJB חסרת מדינה

עבור תרחישים כאלה, ל- EJB יש גרסה חסרת מדינה. המכולה שומרת על מאגר מופע של שעועית, וכל אחד מהם מוחזר לשיטת הקריאה.

הדרך בה אנו מגדירים אותה זהה לסוגי EJB אחרים, עם ממשק מרוחק, ויישום עם javax.ejb. חסר מקום ביאור:

@Stateless הציבור בכיתה FinderEJB מיישם את FinderEJBRemote {אלפבית מפה פרטית; ציבור FinderEJB () {אלפבית = HashMap חדש (); alphabet.put ("A", "Apple"); // הוסף עוד ערכים במפה כאן} חיפוש מחרוזות פומבי (מילת מפתח מחרוזת) {החזר alphabet.get (מילת מפתח); }} 

בואו נוסיף מבחן פשוט נוסף כדי לראות זאת בפעולה:

@Test הציבור בטל givenStatelessBean_whenSearchForA_thenApple () זורק NamingException {assertEquals ("Apple", alphabetFinder.search ("A")); } 

בדוגמה שלעיל, alphabetFinder מוזרק כשדה בכיתת הבדיקה באמצעות ההערה javax.ejb.EJB:

@EJB פרטי FinderEJBRemote alphabetFinder; 

הרעיון המרכזי מאחורי EJBs ללא סטייטס הוא לשפר את הביצועים באמצעות מאגר מופעים של שעועית דומה.

למרות זאת, האביב אינו מנוי לפילוסופיה זו ומציע רק יחידים כחסרי מדינה.

7. שעועית מונעת הודעה == אביב JMS

כל ה- EJB שנדונו עד כה היו שעועית הפעלה. סוג אחר הוא מונע המסרים. כמו שהשם מרמז, הם משמשים בדרך כלל לתקשורת אסינכרונית בין שתי מערכות.

7.1. דוגמה ל- MDB

כדי ליצור Enterprise Java Bean מונע הודעות, עלינו ליישם את ה- javax.jms.MessageListener ממשק המגדיר את onMessage השיטה, והערת את הכיתה כ- javax.ejb.MessageDriven:

@MessageDriven (activationConfig = {@ActivationConfigProperty (propertyName = "destination", propertyValue = "myQueue"), @ActivationConfigProperty (propertyName = "destinationType", propertyValue = "javax.jms.Queue")}) כיתת ציבורי @ הודעה משאבים פרטיים ConnectionFactory connectionFactory; @Resource (name = "ackQueue") ackQueue תור פרטי; בטל ציבורי onMessage (הודעת הודעה) {נסה הודעה {TextMessage textMessage = (TextMessage); מחרוזת ProducPing = textMessage.getText (); אם (producerPing.equals ("מרקו")) {מאשר ("פולו"); }} לתפוס (JMSException e) {לזרוק IllegalStateException חדש (e); }}} 

שים לב שאנחנו מספקים גם כמה תצורות עבור ה- MDB שלנו:

      • destinationType כפי ש תוֹר
      • myQueue כמו יַעַד שם התור, שאליו השעועית שלנו מקשיבה

בדוגמה זו, שלנו מקלט מייצר גם הכרה, ובמובן זה הוא שולח בפני עצמו. זה שולח הודעה לתור אחר שנקרא ackQueue.

עכשיו בואו נראה את זה בפעולה עם מבחן:

@Test ציבורי בטל שניתן MDB_whenMessageSent_thenAcknowledgementReceived () זורק InterruptedException, JMSException, NamingException {חיבור חיבור = connectionFactory.createConnection (); connection.start (); מושב מושב = connection.createSession (שקר, Session.AUTO_ACKNOWLEDGE); מפיק MessageProducer = session.createProducer (myQueue); producer.send (session.createTextMessage ("מרקו")); תגובת MessageConsumer = session.createConsumer (ackQueue); assertEquals ("פולו", ((TextMessage) תגובה. מקבל (1000)). getText ()); } 

פה שלחנו הודעה אל myQueue, שהתקבל על ידי שלנו @MessageDriven ביאור POJO. POJO זה שלח אישור והבדיקה שלנו קיבלה את התגובה כ- MessageConsumer.

7.2. דוגמת JMS באביב

ובכן, עכשיו הגיע הזמן לעשות את אותו הדבר באמצעות אביב!

ראשית, נצטרך להוסיף מעט תצורה למטרה זו. עלינו להעלות הערות על שלנו ApplicationConfig כיתה מלפני עם @EnableJms והוסף כמה שעועית להתקנה JmsListenerContainerFactory ו JmsTemplate:

מחלקה ציבורית @EnableJms ApplicationConfig {@Bean ציבורית DefaultJmsListenerContainerFactory jmsListenerContainerFactory () {DefaultJmsListenerContainerFactory מפעל = חדש DefaultJmsListenerContainerFactory (); factory.setConnectionFactory (connectionFactory ()); מפעל החזרה; } @Bean ConnectionFactory ציבוריות connectionFactory () {להחזיר ActiveMQConnectionFactory חדש ("tcp: // localhost: 61616"); } @Bean JmsTemplate הציבור jmsTemplate () {תבנית JmsTemplate = JmsTemplate חדש (connectionFactory ()); template.setConnectionFactory (connectionFactory ()); תבנית החזרה; }} 

הבא, אנחנו צריכים a יַצרָן - מעיין פשוט רְכִיב - שישלח הודעות אל myQueue ולקבל הכרה מ ackQueue:

@ רכיב ציבורי ציבורי רכיב {@ JmsTemplate פרטי jmTemplate; חלל ציבורי sendMessageToDefaultDestination (הודעת מחרוזת סופית) {jmsTemplate.convertAndSend ("myQueue", הודעה); } מחרוזת publicAcAAck () {return (String) jmsTemplate.receiveAndConvert ("ackQueue"); }} 

ואז, יש לנו מַקְלֵטרְכִיב עם שיטה המסומנת כ- @JmsListener לקבל הודעות באופן אסינכרוני מ- myQueue:

מקלט מחלקה ציבורית ברכיב @ @ @ JmsTemplate פרטי jmTemplate; @JmsListener (destination = "myQueue") קבלת הודעה ציבורית ריקה (מחרוזת msg) {sendAck (); } ריק ריק sendAck () {jmsTemplate.convertAndSend ("ackQueue", "polo"); }} 

זה גם משמש כשולח לאישור קבלת הודעה ב- ackQueue.

כנהוג שלנו, בואו נוודא זאת באמצעות מבחן:

@Test הציבור בטל שניתןJMSBean_whenMessageSent_thenAcknowledgementReceived () זורק NamingException {מפיק מפיק = context.getBean (Producer.class); producer.sendMessageToDefaultDestination ("מרקו"); assertEquals ("פולו", producer.receiveAck ()); } 

במבחן זה שלחנו מרקו ל myQueue וקיבל פּוֹלוֹ כהכרה מאת ackQueue, זהה למה שעשינו עם EJB.

דבר אחד יש לציין כאן Spring JMS יכול לשלוח / לקבל הודעות באופן סינכרוני ואסינכרוני.

8. מסקנה

במדריך זה ראינו א השוואה אחד על אחד של שעועית ג'אווה של Spring ו- Enterprise. הבנו את ההיסטוריה שלהם ואת ההבדלים הבסיסיים.

לאחר מכן עסקנו בדוגמאות פשוטות כדי להדגים את ההשוואה בין שעועית אביב ו EJB. למותר לציין, הוא רק מגרד את פני השטח של מה שהטכנולוגיות מסוגלות, ויש עוד הרבה דברים שאפשר לחקור.

יתר על כן, אלה עשויות להיות טכנולוגיות מתחרות, אך אין זה אומר שאינן יכולות להתקיים יחד. אנו יכולים לשלב בקלות EJBs במסגרת האביב.

כמו תמיד, קוד המקור זמין ב- GitHub.


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