هناك نوعان من الأحمال في Java ، أحدهما محدد من قبل المستخدم ، والآخر هو محمل فئة bootstrap المدمج في JVM.
هناك ثلاثة أنواع من لوادر الفئة المدمجة في JVM ، وهي bootstrap classloader ، و extension classloader (أي extclassloader) ، و classloader النظام (أي appclassloader).
لن أتحدث عن وفد الوالدين عند تحميل JVM ، هناك العديد من المقالات على Javaeye التي تم تقديمها ...
يمكنك إلقاء نظرة على مُنشئاتهم بشكل منفصل ، حيث يتم كتابة محمل صفراء Bootstrap في ج.
java.lang.classloader
ClassLoader المحمي (ClassLoader) {SecurityManager Security True ؛ تهيئة = صواب ؛
هذا المُنشئ له معلمتان وليس مُنشئًا. يمر المُنشئ مع المعلمات في المحمل الأصل من هذا الفئة ، في حين أن المُنشئ بدون معلمات سيعود إلى محمل الفئة التي يتم إرجاعها بواسطة رمز GetSystemClasslasse ()
يتم تعيين initsystemclasslassloader () ccl = getCallerClassloader () ؛ إذا (! عفوًا = null ؛ // يتم تعيين القيمة scl = l.getClassloader () ؛ .... .................................
محمل الفئة الأصل هنا هو SCL ، الذي يتم الحصول عليه بواسطة L.GetClassloader () ، GetClassloader () ، ثم انظر إلى رمز المصدر للمشرف:
Launcher Static Static Private = New Launcher () ؛
القاذفة الثابتة العامة getLauncher () {Return Launcher ؛ ) ؛ AppClassloader ، أي أن GetSystemClassloader إرجاع appclassload = appclassloader.getAppClasslass (extcl) ؛ الخيط ، لمنع الارتباك الناتج عن الحمولة في MultiThReads (أنا أفهم ذلك بنفسي ، هههه) / .......................................... ........................................ .. .............. من هذا نرى أن المحمل الأصل لـ AppClassloader هو extclassloader ، وما هو المحمل الأصل لـ extclassloader؟ دعونا نلقي نظرة على مُنشئ extclassloader:
extclassloader العامة (ملف [] dirs) يلقي ioException
اللودر الوالد فارغ ، في حين أن فئة الوالدين من المستوى الأعلى هي java.lang.classloader.
فئة متزامنة محمية <؟> loadclass (اسم السلسلة ، حل منطقي) يلقي classnotfoundException {// أولاً ، ! = NULL) {// استدعاء المحمل الأصل أولاً ) {إذا لم يتم العثور عليها ، ثم استدعاء industclass للترتيب.هنا ، FindBootStrapClass0 هو استدعاء bootstrap classloader ، أكثر اللودر من الفئة الأساسية ، لتحميل فئة.
أخيرًا ، يمكننا أن نرى أن محمل الفصل الذي تم إرجاعه بواسطة GetSystemClassLoader () هو AppClassloader.
تحليل آلية java classloader
JDK Default ClassLoader
يوفر JDK محمل الفئة التاليين افتراضيًا
loader bootstrp
تتم كتابة Loader bootstrp بلغة C ++. JRE/الفصول.
extclassloader
يقوم محمل bootstrp بتحميل جهاز التحميل المترابط ويقوم بتعيين المحمل الأصل لـ extclassloader على محمل bootstrp. هذه الدلائل جميع الفئات تحت مكتب المسار والفصول في المسار المحدد بواسطة متغير نظام java.ext.dirs.
AppClassloader
بعد تحميل loader bootstrp جهاز التحميل المترابط ، سيتم تحميل appclassloader ، ويتم تحديد المحمل الأصل لـ AppClassloader باعتباره محمل exclassloader. AppClassloader مكتوبة أيضًا في Java. إنه مستند JAR ، وهو أيضًا محمل فئة افتراضي لبرامج Java.
لتلخيص ، يمكن وصف العلاقة بينهما في الشكل التالي:
نموذج وفد الوالدين
يتبنى تحميل ClassLoader في Java آلية مندوب الوالدين.
في الوقت الحالي ، يتحقق ClassLoader ما إذا كانت هذه الفئة قد تم تحميلها من الفصل الذي تم تحميله بالفعل.
كل محمل فئة لديه ذاكرة التخزين المؤقت الخاصة بالتحميل.
عندما لا يتم العثور على ذاكرة التخزين المؤقت للصفوف ، يتم تفويض تحميل الفئة الأصل لتحميله. طريقة لوجود bootstrp classloader.
عندما لا يتم تحميل جميع لوادر فئة الأصل ، يتم تحميلها بواسطة محمل الفئة الحالي ووضعها في ذاكرة التخزين المؤقت الخاصة بها بحيث يمكن إرجاعها مباشرة في المرة القادمة هناك طلب تحميل.
بالحديث عن هذا ، قد تتساءل ، لماذا تتبنى جافا آلية التفويض هذه؟ لفهم هذه المشكلة ، نقدم مفهومًا آخر "مساحة اسم" حول ClassLoader ، مما يعني أنه لتحديد فئة معينة ، تحتاج إلى اسم مؤهل تمامًا للفئة وتحميل هذا الفصل الدراسي لتحديده بشكل مشترك. وهذا يعني ، حتى لو كانت الأسماء المؤهلة تمامًا للفئتين هي نفسها ، لأن قائدي الصعيدين المختلفين يقومون بتحميل هذه الفئة ، فهي فئة مختلفة في JVM. بعد فهم مساحة الاسم ، دعونا نلقي نظرة على نموذج المندوب. بعد تبني نموذج المندوب ، يتم زيادة القدرات التفاعلية لمختلف صناديق الصفوف. يهم برنامجك هناك العديد من لوادر الفصول الدراسية فيه ، لذلك يمكن مشاركة هذه الفئات بالفعل ، والتي تتجنب الارتباك الناتج عن لوادر فئة مختلفة بعد تحميل فئات مختلفة تحمل نفس الاسم.
كيفية تخصيص classloader
بالإضافة إلى ذلك ، يتيح Java أيضًا تخصيص تطبيقات ClassLoader ، إذا كنت ترغب في تخصيصها ، فسنحتاج إلى تنفيذها عن طريق وراثة Java.lang.classload. نحن بحاجة إلى الانتباه إلى عدة طرق مهمة:
1. TovClass طريقة
طريقة loadClass إعلان
الفئة العامة <؟> loadclass (اسم السلسلة) يلقي classnotfoundException
ما سبق هو إعلان النموذج الأولي لطريقة loadClass. دعنا نلقي نظرة على رمز هذه الطريقة لمعرفة كيفية تنفيذ وفد الوالدين.
تنفيذ طريقة loadClass
الفئة العامة <؟> loadclass (اسم السلسلة) يلقي classnotfoundException {return loadclass (name ، false) ؛}مما سبق ، يمكننا أن نرى أن طريقة loadClass تستدعي طريقة LoadCclass (الاسم ، خطأ) ، لذلك دعونا نلقي نظرة على تنفيذ طريقة loadClass أخرى.
فئة LoadClass (اسم السلسلة ، حل منطقي)
فئة متزامنة محمية <؟> loadclass (اسم السلسلة ، حل منطقي) يلقي classnotfoundException {// أولاً ، تحقق مما إذا كان قد تم بالفعل تحميل الفئة C = findloadedClass (name) ؛ // تحقق مما إذا كان قد تم تحميل الفئة إذا (c = = NULL) {try {if (parent! = null) {c = parent.loadClass (name ، false) ؛ } else {c = findBootStrapClass0 (name) ؛ // إذا لم يكن هناك محمل فئة من الوالدين ، فقم بتفويض محمل bootstrap إلى التحميل}} ابحث عن الفصل. }} if (حل) {solveClass (c) ؛في الكود أعلاه ، أضفت تعليقات لمعرفة بوضوح كيف تعمل آلية التفويض الوالد لـ LoadClass. شيء واحد نحتاج إلى ملاحظته هنا هو أن الفئة العامة <؟> loadclass (اسم السلسلة) ترمي ClassNotFoundException غير محددة على أنها نهائية ، مما يعني أنه يمكننا تجاوز هذه الطريقة ، مما يعني أنه يمكن كسر آلية التفويض الأصل. بالإضافة إلى ذلك ، لاحظنا أن هناك طريقة FindClass أعلاه.
2.findClass
نتحقق من رمز المصدر لـ java.lang.classloader ونجد أن تطبيق FindClass هو كما يلي:
فئة محمية <؟> FindClass (اسم السلسلة) يلقي classnotfoundException {رمي classnotfoundexception جديد (الاسم) ؛}يمكننا أن نرى أن التنفيذ الافتراضي لهذه الطريقة هو رمي الاستثناءات مباشرة ، ولكن في الواقع ، يتم ترك هذه الطريقة لتطبيقنا لتجاوز. يعتمد التنفيذ المحدد على منطق التنفيذ الخاص بك. دعونا نصف Defedeclass لاحقًا. حسنًا ، من خلال التحليل أعلاه ، يمكننا استخلاص الاستنتاجات التالية:
عندما نكتب صنفنا الخاص ، إذا كنا نريد متابعة آلية تفويض الوالدين ، فإننا نحتاج فقط إلى تجاوز FindClass.
3
دعونا نلقي نظرة أولاً على الكود المصدري لـ DefereClass:
defedeclass
الفئة النهائية المحمية <؟> defedeclass (اسم السلسلة ، البايت [] B ، int Off ، int len) يلقي classformaterror {return defereeclass (الاسم ، B ، Off ، Len ، Null) ؛}من الكود أعلاه ، يمكننا أن نرى أن هذه الطريقة تُعرف بأنها نهائية ، مما يعني أنه لا يمكن تجاوز هذه الطريقة. يجب أن يتوافق الملف لتعريف الفئات المحددة بواسطة مواصفات الجهاز الظاهري Java. ستستدعي هذه الطريقة أخيرًا الطريقة الأصلية لتنفيذ تحميل الفئة الحقيقية.
حسنًا ، من خلال الوصف أعلاه ، دعونا نفكر في السؤال التالي:
إذا كتبنا فئة java.lang.string بأنفسنا ، هل يمكننا استبدال الفصل الذي يدعو JDK نفسه؟
الجواب لا. لا يمكننا تحقيق ذلك. لماذا؟ أرى العديد من التفسيرات عبر الإنترنت بأن آلية تفويض الوالدين تحل هذه المشكلة ، لكنها في الواقع ليست دقيقة للغاية. نظرًا لأنه يمكن كسر آلية تفويض الوالدين ، يمكنك كتابة أداة تحميل لتحميل java.lang.String التي كتبتها ، لكنك ستجد أنه لن يتم تحميله بنجاح ، على وجه التحديد لأنه للفصل الذي يبدأ بـ Java.*، JVM لقد أكد التنفيذ أنه يجب تحميله بواسطة bootstrp.
السيناريوهات التي لا تتبع "آلية تفويض الوالدين"
ذكر أعلاه أن آلية التفويض الوالد هي إدراك مشكلة التفاعل في الطبقات التي يتم تحميلها بين قوائم الصفوف المختلفين. Loader فئة الوالدين في Java. دعنا نتحدث عن حدوث هذا الموقف.
يوجد معيار SPI (واجهة مزود الخدمة) في Java ، والذي يستخدم مكتبات SPI ، مثل JDBC و JNDI ، إلخ. نعلم جميعًا أن JDBC يحتاج إلى برامج تشغيل مقدمة من أطراف ثالثة ، ويتم وضع حزمة جرة السائق في تطبيقنا نفسه. ClassPath ، و API من JDBC هي جزء من بند JDK ، وقد تم تحميله بواسطة Bootstrp. يقدم Java مفهوم فئة سياق الخيط. برنامج التشغيل ، لا بأس في التحميل من خلال محمل فئة سياق الخيط.
بالإضافة إلى ذلك ، من أجل تطبيق OSGI من فئة أكثر مرونة وبعض خوادم تطبيقات Java ، فإنه يكسر أيضًا آلية تفويض الوالدين.