עד Java 9, אלמנט ארגון הקוד ברמה העליונה של Java היה החבילה. החל מג'אווה 9 שהשתנה: מעל החבילה נמצא כעת המודול. המודול אוסף חבילות קשורות יחד.
מערכת ה- Java Platform Module (JPMS) היא מבנה ברמת קוד, ולכן היא לא משנה את העובדה שאנו אורזים את Java לקבצי JAR. בסופו של דבר, הכל עדיין מקובץ יחד בקבצי JAR. מערכת המודולים מוסיפה מתאר חדש ודרג גבוה יותר בו JAR יכולים להשתמש, על ידי שילוב module-info.java
הקובץ.
אפליקציות וארגונים בקנה מידה גדול ינצלו את המודולים כדי לארגן טוב יותר את הקוד. אבל כולם יצרכו מודולים, מכיוון ש- JDK ושיעוריו מותאמים כעת.
מדוע ג'אווה זקוקה למודולים
JPMS היא התוצאה של פרויקט Jigsaw, שבוצע במטרות המוצהרות הבאות:
- הקל על מפתחים לארגן אפליקציות וספריות גדולות
- שפר את המבנה והאבטחה של הפלטפורמה ושל JDK עצמה
- שפר את ביצועי האפליקציה
- פירוק ידית טוב יותר של הפלטפורמה למכשירים קטנים יותר
ראוי לציין כי JPMS הוא מאפיין SE (מהדורה רגילה), ולכן משפיע על כל היבט של Java מהיסוד. עם זאת, השינוי נועד לאפשר לרוב הקוד לתפקד ללא שינוי במעבר מג'אווה 8 לג'אווה 9. יש לכך כמה יוצאים מן הכלל, ונציין אותם בהמשך הסקירה.
הרעיון העיקרי שעומד מאחורי מודול הוא לאפשר איסוף של חבילות קשורות הגלויות למודול, תוך הסתרת אלמנטים מצרכנים חיצוניים של המודול. במילים אחרות, מודול מאפשר רמה אחרת של אנקפסולציה.
נתיב כיתה לעומת נתיב מודול
בג'אווה עד עכשיו נתיב הכיתה היה השורה התחתונה של מה שזמין ליישום פועל. למרות שדרך הכיתה משרתת מטרה זו ומובנת היטב, היא בסופו של דבר דלי גדול ובלתי מובחן שתוכו כל התלות.
נתיב המודול מוסיף רמה מעל נתיב הכיתה. הוא משמש כמכולה לחבילות וקובע אילו חבילות זמינות ליישום.
מודולים ב- JDK
ה- JDK עצמו מורכב ממודולים כעת. נתחיל בכך שנראה את האומים והברגים של JPMS שם.
אם יש לך JDK במערכת שלך, יש לך גם את המקור. אם אינך מכיר את ה- JDK וכיצד להשיג אותו, עיין במאמר זה.
בתוך ספריית ההתקנות של JDK נמצאת /lib
ספריה. בתוך הספרייה הזו נמצא src.zip
קובץ. לפתוח את זה /src
לספרייה.
חפש בתוך /src
הספריה ונווט /java.base
לספרייה. שם תמצא את module-info.java
הקובץ. תפתח את זה.
לאחר הערות Javadoc בראש, תמצא קטע בשם module java.base
ואחריו סדרת exports
שורות. לא נתעכב על הפורמט כאן מכיוון שהוא נהיה אזוטרי למדי. הפרטים ניתן למצוא כאן.
אתה יכול לראות שרבות מהחבילות המוכרות מג'אווה, כמו java.io
, מיוצאות java.base
מהמודול. זו המהות של מודול שמרכז את החבילות.
הצד השני של ההוראה exports
הוא requires
ההוראה. זה מאפשר לחייב מודול על ידי המודול המוגדר.
בעת הפעלת מהדר Java מול מודולים, אתה מציין את נתיב המודול באופן דומה לנתיב הכיתה. זה מאפשר לפתור את העדויות.
יצירת פרויקט Java מודולרי
בואו נסתכל כיצד בנוי פרויקט Java ממודול.
אנו נכין תוכנית קטנה הכוללת שני מודולים, האחד המספק תלות והשני המשתמש בתלות זו ומייצא מחלקה ראשית ניתנת להפעלה.
צור ספריה חדשה במקום נוח במערכת הקבצים שלך. תקראו לזה /com.javaworld.mod1
. על פי האמנה, מודולי Java חיים בספריה ששמה זהה לזה של המודול.
כעת, בתוך ספריה זו, צור module-info.java
קובץ. בפנים, הוסף את התוכן מרישום 1.
רישום 1: com.javaworld.mod1 / module-info.java
module com.javaworld.mod1 { exports com.javaworld.package1; }
שימו לב שהמודול והחבילה שהוא מייצא הם שמות שונים. אנו מגדירים מודול שמייצא חבילה.
עכשיו ליצור קובץ בנתיב הזה, בתוך הספרייה שמכילה את module-info.java
הקובץ: /com.javaworld.mod1/com/javaworld/package1
. תן שם לקובץ Name.java
. הכניס את תוכנו של רישום 2 לתוכו.
רישום 2: Name.java
package com.javaworld.package1; public class Name { public String getIt() { return "Java World"; } }
רישום 2 יהפוך לכיתה, חבילה ומודול שאנו תלויים בהם.
עכשיו בואו ניצור ספריה נוספת במקביל /com.javaworld.mod1
ונקרא לה /com.javaworld.mod2
. בספריה זו, ניצור module-info.java
הגדרת מודול המייבאת את המודול שכבר יצרנו, כמו ברשימה 3.
רישום 3: com.javaworld.mod2 / module-info.java
module com.javaworld.mod2 { requires com.javaworld.mod1; }
רישום 3 די מובן מאליו. זה מגדיר את com.javaworld.mod2
המודול ומחייב com.javaworld.mod1
.
בתוך /com.javaworld.mod2
הספרייה, ליצור נתיב בכיתה כמו כך: /com.javaworld.mod2/com/javaworld/package2
.
כעת הוסף קובץ בשם Hello.java
, עם הקוד המופיע ברשימה 4.
רישום 4: Hello.java
package com.javaworld.package2; import com.javaworld.package1.Name; public class Hello { public static void main(String[] args) { Name name = new Name(); System.out.println("Hello " + name.getIt()); } }
ברשימה 4, אנו מתחילים בהגדרת החבילה ואז בייבוא com.javawolrd.package1.Name
המחלקה. שימו לב שאלמנטים אלה מתפקדים כמו תמיד. המודולים שינו את האופן שבו החבילות זמינות ברמת מבנה הקובץ, ולא ברמת הקוד.
באופן דומה, הקוד עצמו אמור להיות מוכר לכם. זה פשוט יוצר כיתה וקורא לו שיטה ליצור דוגמה קלאסית של "שלום עולם".
הפעלת דוגמת Java המודולרית
השלב הראשון הוא ליצור ספריות לקבלת הפלט של המהדר. צור ספריה הנקראת /target
בשורש הפרויקט. בפנים, צור ספריה לכל מודול: /target/com.javaworld.mod1
ו- /target/com.javaworld.mod2
.
שלב 2 הוא קומפילציה של מודול התלות והוצאתו /target
לספריה. בבסיס הפרויקט, הזן את הפקודה ברשימה 5. (זה מניח שה- JDK מותקן.)
רישום 5: מודול בניין 1
javac -d target/com.javaworld.mod1 com.javaworld.mod1/module-info.java com.javaworld.mod1/com/javaworld/package1/Name.java
זה יגרום לבניית המקור יחד עם מידע המודול שלו.
שלב 3 הוא ליצור את המודול התלוי. הזן את הפקודה המוצגת ברשימה 6.
רישום 6: מודול בניין 2
javac --module-path target -d target/com.javaworld.mod2 com.javaworld.mod2/module-info.java com.javaworld.mod2/com/javaworld/package2/Hello.java
Let’s take a look at Listing 6 in detail. It introduces the module-path
argument to javac. This allows us to define the module path in similar fashion to the --class-path switch. In this example, we are passing in the target
directory, because that is where Listing 5 outputs Module 1.
Next, Listing 6 defines (via the -d
switch) the output directory for Module 2. Finally, the actual subjects of compilation are given, as the module-info.java
file and class contained in Module 2.
To run, use the command shown in Listing 7.
Listing 7: Executing the module main class
java --module-path target -m com.javaworld.mod2/com.javaworld.package2.Hello
The --module-path
switch tells Java to use /target
directory as the module root, i.e., where to search for the modules. The -m
switch is where we tell Java what our main class is. Notice that we preface the fully qualified class name with its module.
You will be greeted with the output Hello Java World
.
Backward compatibility
You may well be wondering how you can run Java programs written in pre-module versions in the post Java 9 world, given that the previous codebase knows nothing of the module path. The answer is that Java 9 is designed to be backwards compatible. However, the new module system is such a big change that you may run into issues, especially in large codebases.
When running a pre-9 codebase against Java 9, you may run into two kinds of errors: those that stem from your codebase, and those that stem from your dependencies.
For errors that stem from your codebase, the following command can be helpful: jdeps
. This command when pointed at a class or directory will scan for what dependencies are there, and what modules those dependencies rely on.
For errors that stem from your dependencies, you can hope that the package you are depending on will have an updated Java 9 compatible build. If not you may have to search for alternatives.
One common error is this one:
How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
This is Java complaining that a class is not found, because it has migrated to a module without visibility to the consuming code. There are a couple of solutions of varying complexity and permanency, described here.
שוב, אם אתה מגלה שגיאות כאלה עם תלות, בדוק עם הפרויקט. ייתכן שיהיה להם Java 9 לבנות לשימושכם.
JPMS הוא שינוי גורף למדי וזה ייקח זמן לאמץ. למרבה המזל, אין עומס דחוף, מכיוון שג'אווה 8 היא מהדורת תמיכה ארוכת טווח.
עם זאת, בטווח הארוך, פרויקטים ישנים יותר יצטרכו לעבור, ופרויקטים חדשים יצטרכו להשתמש במודולים בצורה מושכלת, בתקווה לנצל חלק מהיתרונות שהובטחו.
סיפור זה, "מה זה JPMS? הצגת מערכת הפלטפורמה של Java" פורסם במקור על ידי JavaWorld.