מה זה OSGi? גישה שונה למודולריות ג'אווה

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

הברית OSGi

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

איך OSGi שונה

הפילוסופיה של OSGi שונה מזו של מסגרות מבוססות ג'אווה אחרות, בעיקר האביב. ב- OSGi, מספר יישומים יכולים להתקיים בתוך אותו מיכל: סביבת זמן הריצה של OSGi . המכולה מבטיחה שכל רכיב יהיה מבודד מספיק, ויש לו גם גישה לכל התלות שהוא דורש. OSGi יכול לתמוך בהזרקת תלות, אשר סטנדרטית על ידי פרוייקט Aries Blueprint. בנוסף לאספקת מיכל ההיפוך של OSGi (IoC), טלה תומך במסגרות Java סטנדרטיות כמו Java Persistence API (JPA).

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

OSGi ב- Eclipse IDE ו- Equinox

OSGi קיים בצורה כלשהי מזה כמה עשורים. הוא משמש ליישומים ידועים רבים, החל מהתקנים ניידים מוטבעים וכלה בשרתי יישומים ו- IDE.

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

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

שימוש ב- OSGi בפרויקט Java: Knoplerfish OSGi

נעבור באמצעות יישום לדוגמא שיהפוך את המושגים של OSGi לקונקרטיים יותר. הדוגמה שלנו מבוססת על זמן הריצה של Knoplerfish OSGi, המשמש בפריסות ייצור רבות. Knoplerfish כולל ממשק GUI וממשק שורת פקודה (CLI) לניהול מיכל OSGi וחבילותיו.

הדבר הראשון שתעשה הוא להוריד את Knoplerfish. הגרסה הנוכחית בזמן כתיבת שורות אלה היא Knoplerfish OSGi 6.1.3. אתה יכול להחליף גרסה זו בכל העדכני ביותר כשאתה קורא מאמר זה.

לאחר שהורדת והתקנת Knoplerfish, להשתמש CLI לרדת לתוך הספרייה שאליה הורדת קובץ JAR, והזן: java -jar framework.jar. זה יפעיל את JAR ההפעלה, ויש לקבל את פניך עם חלון GUI.

ממשק המשתמש OSGi של Knoplerfish

ממשק המשתמש של Knoplerfish OSGi יכול להיראות מכריע בהתחלה, אך היסודות פשוטים:

  • בראש המסך נמצא התפריט.
  • משמאל קבוצה של חבילות שהועמסו בזמן הריצה.
  • מימין חלון מידע.
  • בתחתית קונסולת פלט טקסט.
  • בתחתית ממש קונסולת קלט.
מתיו טייסון

הקלד helpלמסוף הקלט אם ברצונך לראות את אפשרויות העזרה.

לפני שנעבור לדוגמא, נסתכל על מערך חבילות הריצה. תראה חבילה שנקראת HTTP Server, מה שאומר שחבילה שמריצה שרת HTTP קמה. עבור לדפדפן שלך ובדוק // localhost: 8080. בטח מספיק, תראה דף אינטרנט של Knoplerfish.

חבילת 'שלום JavaWorld'

בואו נשתמש בזמן הריצה של OSGi לבניית חבילה פשוטה, אליה אקרא Hello JavaWorld. חבילה זו מוציאה הודעה למסוף.

ברשימה 1 אנו משתמשים ב- Maven לבניית החבילה. יש לה תלות אחת בלבד, המסופקת על ידי הברית OSGi.

רישום 1. תלות OSGi ב- Maven POM

   org.osgi org.osgi.core   

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

רישום 2. התוסף OSGi Felix ב- POM של Maven

   org.apache.felix maven-bundle-plugin true   org.javaworld.osgi org.javaworld.osgi.Hello     

כעת אנו יכולים להסתכל על הכיתה הפשוטה שתפיק "שלום".

רישום 3. שלום חבילה OSGi של JavaWorld

 package com.javaworld.osgi; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class HelloJavaWorld implements BundleActivator { public void start(BundleContext ctx) { System.out.println("Hello JavaWorld."); } public void stop(BundleContext bundleContext) { } } 

בנה את החבילה על ידי מעבר לשורת הפקודה והקלדה mvn clean install. זה יפיק קובץ JAR המכיל את החבילה. כעת, עבור Fileלתפריט בממשק המשתמש של Knoplerfish ובחר Add Bundle. זה יספק דפדפן קבצים. מצא את ה- JAR שבנו זה עתה ובחר אותו.

ניהול חבילות OSGi במיכל

בחלון הפלט של ממשק המשתמש Knoplerfish, תראה הודעת "שלום, JavaWorld". לחץ על הצרור בממשק המשתמש של Knoplerfish ותוכל לראות את המזהה שהמיכל הקצה לו. כאשר אתה מוכן לעצור את החבילה, תוכל ללחוץ על פריט התפריט עצור. דרך נוספת היא להיכנס stop [bundle number]בשורת הפקודה. באפשרותך לנהל חבילות במיכל באמצעות GUI או שורת הפקודה.

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

אינטראקציות צרורות: שירותים ולקוחות

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

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

רישום 4. ממשק חבילת השירות

 package com.javaworld.osgi.service; public interface WhatIsOsgi { public Integer addNum(Integer x, Integer y); } 

רישום 4 הוא ממשק פשוט. השיטה היחידה היא addNum()שיטה שתעשה מה שהיא מרמזת: להחזיר את התוספת של שני מספרים. היישום המוצג ברשימה 5 הוא פשוט באותה מידה אך מוסיף כמה שיטות ספציפיות ל- OSGi.

רישום 5. יישום חבילת השירות

 package com.javaworld.osgi.service; public class WhatIsOsgiImpl implements WhatIsOsgi, BundleActivator { private ServiceReference ref; private ServiceRegistration reg; @Override public Integer addNum(Integer x, Integer y){ return x + y; } @Override public void start(BundleContext context) throws Exception { reg = context.registerService( WhatIsOsgi.class, new WhatIsOsgiImpl(), new Hashtable()); ref = reg.getReference(); } @Override public void stop(BundleContext context) throws Exception { reg.unregister(); } } 

בואו נסתכל מקרוב על מה שקורה ברשימה 5:

  1. public class WhatIsOsgiImpl implements WhatIsOsgi, BundleActivator: כאן אנו מיישמים את הממשק שיצרנו. שימו לב שאנחנו מיישמים גם את BundleActivatorהממשק, כמו שעשינו HelloJavaWorldבדוגמה. האחרון הוא בגלל שחבילה זו תפעיל את עצמה.
  2. private ServiceReference ref; private ServiceRegistration reg;: אלה משתנים עבור שירות הרישום OSGi והתייחסות הצרור לשירות זה, בהתאמה.
  3. public Integer addNum(Integer x, Integer y): זהו היישום הפשוט של שיטת ההוספה.
  4. public void start(BundleContext context): שיטת התחלה זו היא חלק BundleActivatorמהממשק ומבוצעת על ידי המכולה. בדוגמה זו, אנו מקבלים התייחסות לשירות ההרשמה של OSGi ומחילים אותה על WhatIsOsgiהממשק והיישום שלנו . הריק Hashtableהוא עבור מסגרות תצורה, שאיננו משתמשים כאן. אנו מקבלים גם התייחסות לשירות שיצרנו זה עתה.
  5. public void stop(BundleContext context): הנה, אנו פשוט מבטלים את הרישום לשירות. שירות פשוט זה פשוט מנהל את האלמנטים החשובים ביותר במחזור החיים שלו. מטרתה העיקרית היא חשיפת addNumהשיטה למיכל OSGi.

לקוח OSGi

לאחר מכן, בוא נכתוב לקוח שיכול להשתמש בשירות. לקוח זה ישתמש שוב BundleActivatorבממשק. זה גם יוסיף את ServiceListenerהממשק, כפי שמוצג ברשימה 6.

רישום 6. חבילת לקוח שירות OSGi

 public class OsgiClient implements BundleActivator, ServiceListener { private BundleContext ctx; private ServiceReference service; public void start(BundleContext ctx) { this.ctx = ctx; try { ctx.addServiceListener(this, "(objectclass=" + WhatIsOsgi.class.getName() + ")"); } catch (InvalidSyntaxException ise) { ise.printStackTrace(); } } } 

לרישום 6 יש שיטת התחלה שתוסיף מאזין שירותים. מאזין זה מסונן לפי שם המחלקה של השירות שיצרנו ברשימה 5. כאשר השירות מעודכן, הוא יקרא serviceChanged()לשיטה, כפי שמוצג ברשימה 7.

רישום 7. שיטת serviceChanged

 public void serviceChanged(ServiceEvent event) { int type = event.getType(); switch (type){ case(ServiceEvent.REGISTERED): serviceReference = event.getServiceReference(); Greeter service = (Greeter)(ctx.getService(service)); System.out.println("Adding 10 and 100: " + service.addNum(10, 100) ); break; case(ServiceEvent.UNREGISTERING): System.out.println("Service unregistered."); ctx.ungetService(event.getServiceReference()); // Releases reference to service so it can be GC'd break; default: break; } } 

Note that the serviceChanged method is used to determine what event has occurred for a service we are interested in. The service will then respond as specified. In this case, when the REGISTERED event appears, we make use of the addNum() method.

The OSGi alternative

This has been a quick introduction to OSGi, the Open Services Gateway Initiative. As you’ve seen through the Knoplerfish example, OSGi provides a runtime environment where you can define modular Java components (bundles). It provides a defined lifecycle for hosting bundles in the client, and it supports bundles interacting as clients and services within the container. All of these capabilities taken together provide an interesting alternative to standard Java runtimes and frameworks, especially for mobile and IoT applications.

לסיום, שים לב שהמאמר הקודם בסדרה "מה זה: Java" הציג את מערכת Java Platform Module, המציעה גישה שונה לאותו אתגר של מודולריות Java.

סיפור זה, "מה זה OSGi? גישה שונה למודולריות ג'אווה" פורסם במקור על ידי JavaWorld.