החיפוש שלך לא תאם לאף תוצאה.
אנו ממליצים לך לנסות לבצע את הפעולות הבאות כדי למצוא את מה שאתה מחפש:
מה הם ואיך משתמשים בהם
מאת פול דייטל
פול דייטל
במאמר זה אסביר על Java 9 Platform Module System (JPMS), הטכנולוגיה החשובה ביותר להנדסת תוכנה ב-Java מאז הקמתה. מודולריות – התוצאה של פרויקט Jigsaw – עוזרת למפתחים בכל הרמות להיות פרודוקטיביים יותר בבנייה, תחזוקה ופיתוח של מערכות תוכנה, ובעיקר מערכות גדולות.
המודולריות מוסיפה רמה גבוהה יותר של איגוד מעבר לחבילות. רכיב המפתח של השפה החדשה הוא המודול – קבוצה בעלת שם ייחודי וניתנת לשימוש חוזר של חבילות קשורות, כמו גם משאבים (כגון תמונות וקובצי XML) ומתאר מודולים המציין את
פלטפורמת Java SE נמצאת בשימוש משנת 1995. כיום, משתמשים בה כ-10 מיליון מפתחים למגוון מטרות, מבניית יישומים קטנים עבור מכשירים מוגבלים במשאבים – כמו אלה באינטרנט של הדברים (IoT) ובמכשירים משובצים אחרים – ועד פיתוח מערכות קריטיות לעסקים ולמשימה בקנה מידה גדול. עדיין ישנן כמויות אדירות של קוד מדור קודם, אך עד עכשיו, פלטפורמת Java שימשה בעיקר כפתרון אחיד ובלתי-גמיש שחייבים להשתמש בו כמו שהוא. במהלך השנים, היו מאמצים שונים למודולריזציה של Java, אך אף אחד מהם לא נמצא בשימוש נרחב – ואף אחד מהם לא הצליח להפוך את פלטפורמת Java למודולרית.
המודולריזציה של פלטפורמת Java SE הייתה מאתגרת ליישום, והמאמץ לקח שנים רבות. JSR 277: מערכת מודולים ל-Java הוצעה במקור בשנת 2005 עבור Java 7. הבקשה הוחלפה מאוחר יותר על ידי JSR 376: מערכת מודולים לפלטפרמת Java אשר התמקדה ב-Java 8. כעת, פלטפורמת Java SE הפכה למודולרית ב-Java 9, אך רק לאחר ש-Java 9 נדחתה לספטמבר 2017.
כל מודול חייב לציין במפורש את יחסי התלות שלו.
על פי JSR 376, המטרות העיקריות של המודולריזציה של פלטפורמת Java SE הן
JEP 200: ה-JDK המודולרי
JEP 201: קוד מקור מודולרי
JEP 201: תמונות זמני ריצה מודולריות
JEP 260: כימוס ממשקי ה-API הפנימיים ביותר
JEP 201: מערכת מודולרית
JEP 275: אריזת יישומי Java מודולרית
JEP 282: : מקשר המודולים JLINK
JSR 376: מערכת מודולרית בפלטפורמת JAVA
JSR 379: JAVA SE 9
טבלה 1. הצעות (JEPs) ובקשות (JSRs) למודולריות ב-Java
אחד ההיבטים החשובים ביותר ב-Java 9 הוא החלוקה של JDK למודולים לתמיכה בתצורות שונות. (ראו גם "JEP 200: ה-JDK המודולרי." כל ה-JEPs וה-JSRs בנושא מודולריות ב-Java מוצגות בטבלה 1. שימוש בפקודת java מתיקיית ה-bin של ה-JDK עם האפשרות --list-modules
, כלומר:
java --list-modules
מפרט את סל המודולים של ה-JDK, הכולל את המודולים הסטנדרטיים שמיישמים את מפרט Java Language SE (שמות המתחילים ב-java
), מודולים של JavaFX (שמות המתחילים ב-javafx
), מודולים ספציפיים ל-JDK (שמות המתחילים ב-jdk
) ומודולים ספציפיים ל-Oracle (שמות המתחילים ב-oracle
). אחרי כל שם מודול מופיעה מחרוזת גרסה – @9
המציינת שהמודול שייך ל-Java 9.
כפי שהזכרנו, מודול חייב לספק מתאר מודול – מטא-דאטה המציין את יחסי התלות של המודול, את החבילות שהמודול הופך לזמינות למודולים אחרים ועוד. מתאר מודול הוא הגרסה המהודרת של הכרזת מודול המוגדרת בקובץ בשם module-info.java
. כל הצהרת מודול מתחילה במילת המפתח module
, ואחריה שם מודול ייחודי וגוף מודול המוקף בסוגריים מסולסלים:
אחד היתרונות העיקריים של המערכת המודולרית הוא כימוס חזק.
module modulename {
}
גוף הכרזת המודול יכול להיות ריק או להכיל הנחיות מודול שונות, כולל requires
, exports
, provides…with
, uses
ו-opens
(אשר בכל אחת מהן נדון בנפרד). כפי שתראו בהמשך, הידור הצהרת המודול יוצר את מתאר המודול, המאוחסן בקובץ בשם module-info.class
בתיקיית השורש של המודול. כעת נסקור בקצרה את כל הנחיות המודול. בהמשך, נציג הצהרות מודול מעשיות.
מילות המפתח exports
, module
, open
, opens
, provides
, requires
, uses
, with
, כמו גם to
ו transitive
, אשר נציג בהמשך, הן מילות מפתח מוגבלות. הן משמשות כמילות מפתח רק בהצהרות מודול, ואפשר להשתמש בהן כמזהים בשאר הקוד.
requires. הנחיית המודול requires
מציינת שהמודול הנוכחי תלוי במודול אחר. הקשר הזה נקרא יחסי תלות בין מודולים. כל מודול חייב לציין במפורש את יחסי התלות שלו. כאשר למודול א' יש יחס של requires
כלפי מודול ב', פירוש הדבר הוא שמודול א' קורא את מודול ב', ומודול ב' נקרא על ידי מודול א'. כדי לציין תלות במודול אחר, יש להשתמש ב-requires
, באופן הבא:
requires modulename;
ישנה גם הנחיית requires static
, כדי לציין שהמודול נדרש בזמן ההידור אך הוא אופציונלי בזמן ריצה. קשר זה ידוע כתלות אופציונלית, ולא נדון בו במאמר הזה.
requires transitive – קריאוּת משתמעת. כדי לציין תלות במודול אחר ולהבטיח שמודולים אחרים שקוראים את המודול שלכם קוראים גם את יחסי התלות האלה – דבר הידוע בשם קריאוּת משתמעת – השתמשו ב-requires transitive
, כך:
requires transitive modulename;
שימו לב להנחיה הבאה מהכרזת המודול java.desktop
:
requires transitive java.xml
;
במקרה כזה, כל מודול שקורא את java.desktop
קורא גם במשתמע את java.xml
. לדוגמה, אם שיטה ממודול java.desktop
מחזירה טיפוס ממודול java.xml
, הקוד שבמודולים שקוראים את java.desktop
יהיה תלוי ב-java.xml
. ללא ההנחיה requires transitive
בהכרזת המודול של java.desktop
, המודולים התלויים האלה לא יהודרו אלא אם כן הם יקראו באופן מפורש את java.xml
.
לפי JSR 379, המודולים הסטנדרטיים של Java SE חייבים להעניק קריאות משתמעת בכל המקרים כמו זה שמתואר כאן. כמו כן, למרות שמודול סטנדרטי של Java SE עשוי להיות תלוי במודולים לא סטנדרטיים, אסור לו להעניק להם קריאות משתמעת. הדבר מבטיח שקוד התלוי רק במודולים סטנדרטיים של Java SE יהיה נייד בכל יישומי Java SE.
exports and exports…to. הנחיית המודול exports
מציינת את אחת מחבילות המודול שהטיפוסים מסוג public
שלהן (והטיפוסים מסוג public
ו-protected
המקוננים שלהן) צריכים להיות נגישים לקוד בכל המודולים האחרים. הנחיה exports…to
מאפשרת לציין ברשימה מופרדת בפסיקים בדיוק את המודול או המודולים שהקוד שלהם יכול לגשת לחבילה המיוצאת – דבר הידוע כיצוא מוסמך.
uses. הנחיית המודול uses
מציינת שירות שבו המודול משתמש – מה שהופך את המודול לצרכן שירות. service הוא אובייקט של מחלקה שמיישמת את הממשק או מרחיבה את מחלקת abstract
שצוינה בהנחיה uses
.
provides…with. הנחיית המודול provides…with
מציינת שהמודול מספק יישום של שירות – מה שהופך את המודול לספק שירות. החלק provides
של ההנחיה מציין ממשק או מחלקת abstract
הרשומים בהנחיה uses
של המודול, וחלק with
של ההנחיה מציין את שם מחלקת ספק השירות שמיישם (implements
) את הממשק או מרחיב (extends
) את המחלקה abstract
.
open, opens, and opens…to. לפני Java 9, היה אפשר להשתמש ב-reflection כדי ללמוד על כל הטיפוסים בחבילה ועל כל איברי הטיפוסים – אפילו איברים שהם private
– בין אם רציתם לאפשר את היכולת הזו או לא. לכן, שום דבר לא באמת היה מכומס.
אחד היתרונות העיקריים של המערכת המודולרית הוא כימוס חזק. כברירת מחדל, הטיפוסים במודול אינם נגישים למודולים אחרים, אלא אם כן הם ציבוריים וגם ביצעתם יצוא לחבילה שלהם. אתם חושפים רק את החבילות שאתם רוצים לחשוף. עם Java 9, הדבר חל גם על reflection.
אפשור גישה בזמן ריצה בלבד לחבילה. הנחיית מודול פותח של הטופס
opens package
מציינת שטיפוסים ספציפיים מסוג public
של חבילה מסוימת (והטיפוסים מסוג public
ו-protected
המקוננים שלהם) נגישים לקוד במודולים אחרים בזמן ריצה בלבד. כמו כן, כל הטיפוסים בחבילה שצוינה (וכל איברי הטיפוסים) נגישים באמצעות reflection.
אפשור גישה בזמן ריצה בלבד לחבילה על ידי מודולים ספציפיים. הנחיית המודול opens…to
מסוג
opens package to comma-separated-list-of-modules
מציינת שטיפוסים ספציפיים מסוג public
של חבילה מסוימת (והטיפוסים מסוג public
ו-protected
המקוננים שלהם) נגישים לקוד במודולים המפורטים בזמן ריצה בלבד. כל הטיפוסים בחבילה שצוינה (וכל איברי הטיפוסים) נגישים באמצעות reflection לקוד במודולים שצוינו.
אפשור גישה בזמן ריצה בלבד לכל החבילות במודול. אם כל החבילות במודול צריכות להיות נגישות בזמן ריצה ובאמצעות reflection לכל המודולים האחרים, אפשר לפתוח (open
) את המודול כולו, באופן הבא:
open module modulename {
// module directives
}
כברירת מחדל, מודולים עם גישה רפלקטיבית בזמן ריצה לחבילה מסוימת יכולים לראות את הטיפוסים מסוג public
של החבילה ואת הטיפוסים מסוג public
ו-protected
המקוננים שלהם. עם זאת, הקוד במודולים אחרים יכול לגשת לכל הטיפוסים בחבילה שנחשפה ולכל האיברים בתוך טיפוסים אלה, כולל איברים שהם private
, דרך setAccessible
, כמו בגרסאות קודמות של Java.
למידע נוסף על setAccessible
ועל reflection, עיינו בתיעוד של Oracle.
פול דייטל, מנכ"ל ומנהל טכני ראשי של Deitel & Associates, הוא בוגר MIT עם 35 שנות ניסיון במחשוב. הוא אלוף Java ומתכנת ב-Java כבר יותר מ-22 שנה. הוא והמחבר השותף, ד"ר הארווי מ. דייטל, הם המחברים הנמכרים ביותר בעולם לשפות תכנות. פול העביר קורסי תכנות Java, Android, iOS, C#, C++, C, ותכנות באינטרנט ללקוחות רבים בתעשייה וללקוחות ממשלתיים ואקדמיים ברחבי העולם.
הערה: מאמר זה הוא קטע ממאמר שהופיע ב- Java Magazine בספטמבר/אוקטובר 2017.