عند القيام بتطوير Java ، فإن المعرفة الأساسية التي يجب أن تكون على دراية بها في آلية charloader. يلخص هذه المقالة باختصار آلية java classloader. نظرًا لأن تطبيقات JVM مختلفة مختلفة ، فإن المحتوى الموضح في هذه المقالة يقتصر على نقطة Hotspot JVM.
ستبدأ هذه المقالة مع الجوانب الأربعة لـ ClassLoader ، نموذج الوالدين الوالدين المقدمة من JDK ، كيفية تخصيص scenloader والسيناريوهات التي تكسر آلية التفويض الوالدين في Java.
JDK Default ClassLoader
يوفر JDK محمل الفئة التاليين افتراضيًا
loader bootstrp
يتم كتابة محمل bootstrp بلغة C ++. يتم تهيئته بعد بدء تشغيل الجهاز الظاهري Java. إنه مسؤول بشكل أساسي عن تحميل المسار المحدد بواسطة ٪ java_home ٪/jre/lib ، معلمة -xbootclasspath والفئات في ٪ java_home ٪/jre/classes.
extclassloader
يقوم Loader Bootstrp بتحميل جهاز تحميل التحميل الصحيح ، ويقوم بتعيين المحمل الأصل لـ extClassLoader إلى bootstrp loader.extClassloader مكتوبة في Java ، على وجه التحديد ، sun.misc.launcher $ extclassloader. يقوم جهاز التشغيل ExtClassLoader بشكل أساسي بتحميل ٪ java_home ٪/JRE/lib/ext ، جميع الفئات الدلائل تحت هذا المسار ومكتبات الفصل في المسار المحدد بواسطة متغير نظام java.ext.dirs.
AppClassloader
بعد تحميل loader bootstrp جهاز التحميل المترابط ، سيتم تحميل appclassloader ، ويتم تحديد المحمل الأصل لـ AppClassloader باعتباره محمل exclassloader. AppClassloader مكتوب أيضًا في Java. فئة التنفيذ الخاصة بها هي sun.misc.launcher $ appclassloader. بالإضافة إلى ذلك ، نعلم أن هناك طريقة getSystemClassLoader في ClassLoader. تقوم هذه الطريقة بإرجاع appclassloader.appclassloader مسؤول بشكل أساسي عن تحميل وثيقة الفئة أو الجرة في الموقع المحدد بواسطة ClassPath. إنه أيضًا محمل الفئة الافتراضية لبرامج Java.
نموذج وفد الوالدين
يتبنى تحميل classloader في Java آلية مندوب الوالدين. عند تحميل الفئات باستخدام آلية مندوب الوالدين ، يتم اعتماد الخطوات التالية:
حاليًا ، يتحقق ClassLoader أولاً مما إذا كان قد تم تحميل هذه الفئة من الفصل الذي تم تحميله بالفعل. إذا تم تحميله ، فسوف يعيد مباشرة الفئة الأصلية.
كل لوادر فئة لديه ذاكرة التخزين المؤقت الخاصة بتحميلها. عند تحميل فئة ، سيتم وضعها في ذاكرة التخزين المؤقت ويمكن إرجاعها مباشرة عند تحميلها في المرة القادمة.
عند عدم العثور على ذاكرة التخزين المؤقت لـ ClassLoader ، يتم تفويض تحميل الفئة الأصل للتحميل. يتبنى محمل الطبقة الوالدية نفس الاستراتيجية. أولاً ، تحقق من ذاكرة التخزين المؤقت الخاصة بها ، ثم تفويض الفئة الأم لفئة الأصل لتحميلها ، على طول الطريق إلى bootstrp classloader.
عندما لا يتم تحميل جميع لوادر فئة الأصل ، يتم تحميلها بواسطة محمل الفئة الحالي ووضعها في ذاكرة التخزين المؤقت الخاصة بها بحيث يمكن إرجاعها مباشرة في المرة القادمة هناك طلب تحميل.
بالحديث عن هذا ، قد تتساءل ، لماذا تتبنى جافا آلية التفويض هذه؟ لفهم هذه المشكلة ، نقدم مفهومًا آخر "مساحة اسم" حول ClassLoader ، مما يعني أنه لتحديد فئة معينة ، تحتاج إلى اسم مؤهل تمامًا للفئة وتحميل هذا الفصل الدراسي لتحديده بشكل مشترك. وهذا يعني ، حتى لو كانت الأسماء المؤهلة تمامًا للفئتين هي نفسها ، لأن قائدي الصعيدين المختلفين يقومون بتحميل هذه الفئة ، فهي فئة مختلفة في JVM. بعد فهم مساحة الاسم ، دعونا نلقي نظرة على نموذج المندوب. بعد تبني نموذج المندوب ، يتم زيادة القدرات التفاعلية لمختلف محولات الصفوف. على سبيل المثال ، كما هو مذكور أعلاه ، فإن مكتبات الفصل التي توفرها JDK Binsheng ، مثل HashMap ، LinkedList ، وما إلى ذلك. بعد تحميل هذه الفئات بواسطة محمل فئة Bootstrp ، بغض النظر عن عدد اللوادر الفئة الموجودة في برنامجك ، يمكن مشاركة هذه الفئات فعليًا ، والتي تتجنب الالتباس الناتج عن لوادر فئة مختلفة تحميل فصول مختلفة من الاسم نفسه.
كيفية تخصيص classloader
بالإضافة إلى جهاز تحميل الفئة المقدم بشكل افتراضي المذكور أعلاه ، تسمح Java أيضًا للتطبيقات بتخصيص جهاز تحميل الفئة. إذا كنت ترغب في تخصيص جهاز تحميل classloader ، فنحن بحاجة إلى تنفيذه عن طريق وراثة java.lang.classloader. بعد ذلك ، دعونا نلقي نظرة على العديد من الطرق المهمة التي نحتاجها إلى الانتباه إليها عند تخصيص جهاز تحميل الفصل:
1. TovClass طريقة
طريقة loadClass إعلان
الفئة العامة <؟> loadclass (اسم السلسلة) يلقي classnotfoundException
ما سبق هو إعلان النموذج الأولي لطريقة loadClass. يتم تنفيذ تنفيذ آلية تفويض الوالدين المذكورة أعلاه بالفعل في هذه الطريقة. دعنا نلقي نظرة على رمز هذه الطريقة لمعرفة كيفية تنفيذ وفد الوالدين.
تنفيذ طريقة loadClass
الفئة العامة <؟> loadclass (اسم السلسلة) يلقي classnotfoundException {return loadclass (name ، false) ؛}مما سبق ، يمكننا أن نرى أن طريقة loadClass تستدعي طريقة LoadCclass (الاسم ، خطأ) ، لذلك دعونا نلقي نظرة على تنفيذ طريقة loadClass أخرى.
فئة LoadClass (اسم السلسلة ، حل منطقي)
فئة متزامنة محمية <؟> loadclass (اسم السلسلة ، حل منطقي) يلقي classnotfoundException {// أولاً ، تحقق مما إذا كان قد تم بالفعل تحميل الفئة C = findloadedClass (name) ؛ // تم تحديد Loader ، يتم تفويض المحمل الأصل للتحميل. } آخر {c = findbootsstrapclass0 (name) ؛ // إذا لم يكن هناك محمل فئة من الوالدين ، فافوض عملية تحميل bootstrap لتحميل}} catch (classnotfoundexception e) {// إذا لم يتم العثور عليها ، ثم استدعاء FindClass بالترتيب // للعثور على الفئة. C = FindClass (name) ؛ // إذا لم يتم تحميل تحميل الفئة الأصل ، فسيتم تحميله من خلال FindClass الخاصة به. }} if (حل) {sesolveClass (c) ؛} return c ؛}في الكود أعلاه ، أضفت تعليقات لمعرفة بوضوح كيف تعمل آلية التفويض الوالد لـ LoadClass. شيء واحد نحتاج إلى ملاحظته هنا هو أن الفئة العامة <؟> loadclass (اسم السلسلة) ترمي ClassNotFoundException غير محددة على أنها نهائية ، مما يعني أنه يمكننا تجاوز هذه الطريقة ، مما يعني أنه يمكن كسر آلية التفويض الأصل. بالإضافة إلى ذلك ، لاحظنا أن هناك طريقة FindClass أعلاه. بعد ذلك ، دعنا نتحدث عما إذا كانت هذه الطريقة سيئة.
2.findClass
نتحقق من رمز المصدر لـ java.lang.classloader ونجد أن تطبيق FindClass هو كما يلي:
فئة محمية <؟> FindClass (اسم السلسلة) يلقي classnotfoundException {رمي classnotfoundexception جديد (الاسم) ؛}يمكننا أن نرى أن التنفيذ الافتراضي لهذه الطريقة هو رمي الاستثناءات مباشرة ، ولكن في الواقع ، يتم ترك هذه الطريقة لتطبيقنا لتجاوز. يعتمد التنفيذ المحدد على منطق التنفيذ. يمكنك القراءة من القرص أو الحصول على دفق بايت من ملفات الفصل من الشبكة. بعد الحصول على الفئة الثنائية ، يمكنك تسليمها إلى DefereClass لمزيد من التحميل. دعونا نصف Defedeclass لاحقًا. حسنًا ، من خلال التحليل أعلاه ، يمكننا استخلاص الاستنتاجات التالية:
عندما نكتب صنفنا الخاص ، إذا كنا نريد متابعة آلية تفويض الوالدين ، فإننا نحتاج فقط إلى تجاوز FindClass.
3
دعونا نلقي نظرة أولاً على الكود المصدري لـ DefereClass:
defedeclass
الفئة النهائية المحمية <؟> defedeclass (اسم السلسلة ، البايت [] B ، int Off ، int len) يلقي classformaterror {return defereeclass (الاسم ، B ، Off ، Len ، Null) ؛}من الكود أعلاه ، يمكننا أن نرى أن هذه الطريقة يتم تعريفها على أنها نهائية ، مما يعني أنه لا يمكن تجاوز هذه الطريقة. في الواقع ، هذا هو أيضًا الإدخال الوحيد الذي تركته لنا JVM. من خلال هذا الإدخال الفريد ، يضمن JVM أن ملف الفئة يجب أن يمتثل لتعريف الفئة المحددة في مواصفات الجهاز الظاهري Java. ستستدعي هذه الطريقة أخيرًا الطريقة الأصلية لتنفيذ تحميل الفئة الحقيقية.
حسنًا ، من خلال الوصف أعلاه ، دعونا نفكر في السؤال التالي:
إذا كتبنا فئة java.lang.string بأنفسنا ، هل يمكننا استبدال الفصل الذي يدعو JDK نفسه؟
الجواب لا. لا يمكننا تحقيق ذلك. لماذا؟ أرى العديد من التفسيرات عبر الإنترنت بأن آلية تفويض الوالدين تحل هذه المشكلة ، لكنها في الواقع ليست دقيقة للغاية. نظرًا لأنه يمكن كسر آلية تفويض الوالدين ، يمكنك كتابة أداة تحميل لتحميل java.lang.string التي كتبتها ، لكنك ستجد أنه لن يتم تحميله بنجاح. على وجه التحديد ، بالنسبة للفئات التي تبدأ من Java.*، فقد ضمن تنفيذ JVM أنه يجب تحميله بواسطة bootstrp.
السيناريوهات التي لا تتبع "آلية تفويض الوالدين"
ذكر أعلاه أن آلية تفويض الوالدين هي إدراك مشكلة التفاعل في الطبقات التي يتم تحميلها بين قائدي الدرجة المختلفين. يتم تسليم الفصول التي يشاركها الجميع إلى المحمل الأصل لتحميلها ، ولكن هناك بالفعل موقف في Java حيث تحتاج الفصول التي تم تحميلها بواسطة محمل الفئة الأصل إلى استخدام فئات محملة بواسطة محمل الطفل. دعنا نتحدث عن حدوث هذا الموقف.
يوجد معيار SPI (ServiceProviderInterface) في Java يستخدم مكتبات SPI ، مثل JDBC و JNDI ، وما إلى ذلك. نعلم جميعًا أن JDBC يتطلب برامج تشغيل مقدمة من أطراف ثالثة ، ويتم وضع حزمة جرة السائق في فئة تطبيقنا نفسه. واجهة برمجة تطبيقات JDBC نفسها هي جزء من JDK التي توفرها JDK ، وتم تحميلها بواسطة bootstrp. فكيف يمكنني تحميل فئات التنفيذ التي توفرها مصنعي الطرف الثالث؟ تقدم Java مفهوم تحميل فئة سياق الخيط. سوف يرث محمل فئة مؤشرات الترابط من مؤشر ترابط الأصل بشكل افتراضي. إذا لم يتم تحديده ، فإن الافتراضي هو محمل فئة النظام (AppClassLoader). وبهذه الطريقة ، عند تحميل برنامج تشغيل جهة خارجية ، يمكن تحميله من خلال محمل فئة سياق الخيط.
بالإضافة إلى ذلك ، من أجل تطبيق OSGI من فئة أكثر مرونة وبعض JavaAppservers ، فإنه يكسر أيضًا آلية تفويض الوالدين.
لخص
ما ورد أعلاه هو كل محتوى هذه المقالة حول تحليل رمز استخدام واستخدام آلية java classloader. آمل أن يكون ذلك مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!