מעמיסי כיתה בג'אווה

1. מבוא למעמיסי כיתות

אחראים על מעמיסי כיתות טעינת שיעורי Java במהלך זמן ריצה באופן דינמי ל- JVM (Java Virtual Machine). כמו כן, הם חלק מ- JRE (Java Runtime Environment). לפיכך, ה- JVM אינו צריך לדעת על הקבצים הבסיסיים או מערכות הקבצים על מנת להריץ תוכניות Java בזכות מעמיסי כיתה.

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

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

2. סוגי מעמיסי כיתה מובנים

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

בטל ציבורי printClassLoaders () זורק את ClassNotFoundException {System.out.println ("Classloader של מחלקה זו:" + PrintClassLoader.class.getClassLoader ()); System.out.println ("Classloader of Logging:" + Logging.class.getClassLoader ()); System.out.println ("Classloader של ArrayList:" + ArrayList.class.getClassLoader ()); }

כאשר מבוצעת הדפסת השיטה לעיל:

מטעין מחלקה מהמחלקה הזו: [מוגן באמצעות דוא"ל] מטען כיתה של רישום: [מוגן באמצעות דוא"ל] מטען כיתות של ArrayList: null

כפי שאנו רואים, יש כאן שלושה מעמיסי כיתה שונים; יישום, סיומת ו- bootstrap (מוצג כ ריק).

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

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

לבסוף, ה- bootstrap אחד טוען את ה- רשימת מערך מעמד. מטעין bootstrap או מטען כיתות ראשוני הוא ההורה של כל האחרים.

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

בואו נדון בפירוט רב יותר על כל אחד ממעמיסי הכיתה הללו.

2.1. Bootstrap Class Loader

שיעורי Java נטענים על ידי מופע של java.lang.ClassLoader. עם זאת, מעמיסי כיתות הם שיעורים בעצמם. מכאן, השאלה היא מי טוען את java.lang.ClassLoader את עצמה?

כאן נכנס לתמונה מטען האתחול או מטעין הכיתה הראשוני.

היא אחראית בעיקר לטעינת שיעורים פנימיים של JDK, בדרך כלל rt.jar וספריות ליבה אחרות הממוקמות ב ספריה $ JAVA_HOME / jre / lib. בנוסף, מטעין כיתת Bootstrap משמש כהורה לכל האחרים ClassLoader מקרים.

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

2.2. מטעין מחלקות הרחבה

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

עומסי מטעני מחלקות הרחבה מספריית הרחבות JDK, בדרך כלל $ JAVA_HOME / lib / ext ספריה או כל ספריה אחרת המוזכרת ב- java.ext.dirs נכס מערכת.

2.3. מטעין מחלקות מערכת

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

3. כיצד עובדים מעמיסי כיתה?

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

ה java.lang.ClassLoader.loadClass () השיטה אחראית לטעינת הגדרת הכיתה לזמן ריצה. הוא מנסה לטעון את הכיתה על בסיס שם מלא.

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

בסופו של דבר, אם מעמיס כיתת ההורים לא ימצא את הכיתה, אז כיתת הילדים תתקשר java.net.URLClassLoader.findClass () שיטה לחפש שיעורים במערכת הקבצים עצמה.

אם גם מטעין הכיתות האחרון לא מסוגל לטעון את הכיתה, הוא זורק java.lang.NoClassDefFoundError אוֹ java.lang.ClassNotFoundException.

בואו נסתכל על דוגמה לפלט כאשר ClassNotFoundException נזרק.

java.lang.ClassNotFoundException: com.baeldung.classloader.SampleClassLoader ב- java.net.URLClassLoader.findClass (URLClassLoader.java:381) ב- java.lang.ClassLoader.loadClass (ClassLoader.java:424) ב- java.lang.ClassLoader. loadClass (ClassLoader.java:357) ב- java.lang.Class.forName0 (שיטה מקורית) ב- java.lang.Class.forName (Class.java:348)

אם נעבור את השתלשלות האירועים ממש מהתקשרות java.lang.Class.forName ()נוכל להבין שהוא מנסה תחילה לטעון את הכיתה באמצעות מטעין כיתות הורים ואז java.net.URLClassLoader.findClass () לחפש את הכיתה עצמה.

כשזה עדיין לא מוצא את הכיתה, זה זורק א ClassNotFoundException.

יש שלוש תכונות חשובות של מעמיסי כיתה.

3.1. מודל משלחת

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

נניח שיש לנו בקשה לטעון מחלקת יישומים ל- JVM. מטעין מחלקות המערכת מאציל תחילה את הטעינה של אותה מחלקה למעמיס הכיתות של הרחבת האב אשר בתורו מאציל אותה למעמיס המחלקה bootstrap.

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

3.2. שיעורים ייחודיים

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

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

3.3. רְאוּת

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

למשל, מחלקות שנטענות על ידי מטעין מחלקות המערכת יכולות לראות את הכיתות שנטענות על ידי מעמיסי המחלקה של ה- Extension ו- Bootstrap, אך לא להפך.

כדי להמחיש זאת, אם Class A נטען על ידי מטעין מחלקות יישומים ומחלקה B נטען על ידי מטעין מחלקות הרחבות, אזי מחלקות A ו- B נראות לעין בכל הנוגע למחלקות אחרות הנטענות על ידי מטען מחלקות היישום.

בכל זאת, מחלקה ב 'היא המחלקה היחידה הנראית מבחינת מחלקות אחרות שטעונות מטעין הכיתות הרחבה.

4. ClassLoader מותאם אישית

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

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

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

4.1. מטעני שימוש בכיתות מותאמות אישית

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

  1. עזרה בשינוי קוד הביץ הקיים, למשל. סוכני אריגה
  2. יצירת שיעורים המתאימים באופן דינמי לצרכי המשתמש. למשל ב- JDBC, מעבר בין יישומי נהג שונים נעשה באמצעות טעינת מחלקות דינמיות.
  3. הטמעת מנגנון גרסאות מחלקה תוך טעינת קודי בתים שונים עבור כיתות עם אותם שמות וחבילות. ניתן לעשות זאת באמצעות מטעין מחלקות כתובות URL (טעינות צנצנות באמצעות כתובות URL) או מעמיסי מחלקה מותאמים אישית.

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

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

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

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

4.2. יצירת מטעני הכיתה המותאמים אישית שלנו

לצורך המחשה, נניח שעלינו לטעון שיעורים מקובץ באמצעות מטעין מחלקה מותאם אישית.

עלינו להאריך את ClassLoader בכיתה ולדרוס את findClass () שיטה:

מחלקה ציבורית CustomClassLoader מרחיב את ClassLoader {@Override public ClassClassClass (שם מחרוזת) זורק ClassNotFoundException {בייט [] b = loadClassFromFile (שם); return defineClass (שם, b, 0, b.length); } בתים פרטיים [] loadClassFromFile (מחרוזת קובץ שם) {InputStream inputStream = getClass (). getClassLoader (). getResourceAsStream (fileName.replace ('.', File.separatorChar) + ".class"); מאגר בתים []; ByteArrayOutputStream byteStream = ByteArrayOutputStream חדש (); int nextValue = 0; נסה {while ((nextValue = inputStream.read ())! = -1) {byteStream.write (nextValue); }} לתפוס (IOException e) {e.printStackTrace (); } חיץ = byteStream.toByteArray (); חיץ החזרה; }}

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

5. הבנה java.lang.ClassLoader

בואו נדון בכמה שיטות חיוניות מה- java.lang.ClassLoader בכיתה כדי לקבל תמונה ברורה יותר איך זה עובד.

5.1. ה loadClass () שיטה

class ClassClass (שם מחרוזת, פתרון בוליאני) זורק ClassNotFoundException {

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

המכונה הווירטואלית של Java קוראת loadClass () שיטה לפתרון הגדרות הפניות לכיתה נָכוֹן. עם זאת, לא תמיד יש צורך לפתור שיעור. אם רק עלינו לקבוע אם המחלקה קיימת או לא, פרמטר ה- resolve מוגדר כ- שֶׁקֶר.

שיטה זו משמשת כנקודת כניסה למטען הכיתות.

אנו יכולים לנסות להבין את העבודה הפנימית של ה- loadClass () שיטה מקוד המקור של java.lang.ClassLoader:

Class loadClass מוגן (שם מחרוזת, פיתרון בוליאני) זורק ClassNotFoundException {מסונכרן (getClassLoadingLock (שם)) {// ראשית, בדקו אם המחלקה כבר נטענה Class c = findLoadedClass (name); אם (c == null) {long t0 = System.nanoTime (); נסה {if (הורה! = null) {c = parent.loadClass (שם, שקר); } אחר {c = findBootstrapClassOrNull (שם); }} לתפוס (ClassNotFoundException e) {// ClassNotFoundException נזרק אם המחלקה לא נמצאה // ממטעין המחלקה האב שאינו null} אם (c == null) {// אם עדיין לא נמצא, אז הפעל את findClass על מנת // ל- למצוא את הכיתה. c = findClass (שם); }} אם (לפתור) {לפתורקלאס (ג); } להחזיר ג; }}

יישום ברירת המחדל של השיטה מחפש שיעורים בסדר הבא:

  1. מזמין את findLoadedClass (מחרוזת) שיטה כדי לראות אם הכיתה כבר טעונה.
  2. מזמין את loadClass (מחרוזת) שיטה על מעמיס כיתת האם.
  3. קרא את findClass (מחרוזת) שיטה למצוא את הכיתה.

5.2. ה defineClass () שיטה

Class final final מוגן Class (שם מחרוזת, בתים [] b, int off, int len) זורק ClassFormatError

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

במקרה והנתונים לא הכילו מחלקה חוקית, הם משליכים א ClassFormatError.

כמו כן, איננו יכולים לעקוף שיטה זו מכיוון שהיא מסומנת כסופית.

5.3. ה findClass () שיטה

מחלקה מוגנת findClass (שם מחרוזת) זורק ClassNotFoundException

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

גַם, loadClass () קורא לשיטה זו אם מעמיס הכיתה ההורה לא מצא את הכיתה המבוקשת.

יישום ברירת המחדל זורק א ClassNotFoundException אם אף הורה למטען הכיתות לא מוצא את הכיתה.

5.4. ה getParent () שיטה

גמר ציבורי ClassLoader getParent ()

שיטה זו מחזירה את מטעין המחלקה האב להאצלה.

יש יישומים כמו אלה שנראו קודם בסעיף 2. ריק כדי לייצג את מטעין הכיתה bootstrap.

5.5. ה getResource () שיטה

כתובת אתר ציבורית getResource (שם מחרוזת)

שיטה זו מנסה למצוא משאב עם השם הנתון.

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

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

הוא מחזיר אובייקט URL לקריאת המשאב, או null אם לא ניתן למצוא את המשאב או אם למזמין אין הרשאות מתאימות להחזרת המשאב.

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

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

6. מעמיסי כיתות הקשר

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

כמו שלמדנו בעבר, מעמיסי כיתה ב- JVM עוקבים אחר מודל היררכי כך שלכל מטעין כיתות יש הורה יחיד, למעט מעמיס הכיתות bootstrap.

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

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

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

ה java.lang. חוט בכיתה יש שיטה getContextClassLoader () שמחזירה את ContextClassLoader לחוט המסוים. ה ContextClassLoader מסופק על ידי יוצר השרשור בעת טעינת משאבים ושיעורים.

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

7. מסקנה

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

דיברנו על סוגים שונים של מעמיסי כיתה, כלומר - Bootstrap, Extensions ו- System loaders. Bootstrap משמש כהורה לכולם ואחראי לטעינת הכיתות הפנימיות של JDK. לעומת זאת, תוספות ומערכת טוענות מחלקות מספריית התוספות של ג'אווה ומנתיב הכיתות בהתאמה.

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

דוגמאות קוד, כמו תמיד, ניתן למצוא באתר GitHub.


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