لاكتساب فهم أعمق لـ ClassLoader ، يجب أولاً معرفة ما الذي يستخدمه ClassLoader. كما يوحي الاسم ، يتم استخدامه لتحميل ملفات الفئة في JVM لاستخدامها من قبل البرنامج. نحن نعلم أن برامج Java يمكنها تحميل تعريفات الفئة ديناميكيًا ، ويتم تنفيذ آلية التحميل الديناميكية هذه من خلال charloader ، بحيث يمكنك أن تتخيل مدى أهمية جهاز تحميل الفئة.
بعد رؤية ذلك ، قد يفكر بعض الأصدقاء في سؤال ، أي منذ استخدام ClassLoader لتحميل الفصول في JVM ، كيف يتم تحميل ClassLoader؟ أليست فئة جافا؟
هذا صحيح ، هناك بالفعل محمل فئة هنا غير مكتوب بلغة Java ، ولكنه جزء من تطبيق JVM. هذا classloader هو bootstrap classloader (لوادر فئة البدء) ، يقوم هذا classloader بتحميل واجهة برمجة تطبيقات Java Core عندما يتم تشغيل JVM لتلبية الاحتياجات الأساسية لبرنامج Java ، بما في ذلك جهاز تحميل الفئة المعرفة من قبل المستخدم. يشير ما يسمى بـ ClassLoader المعرفة من قبل المستخدم هنا إلى جهاز التحميل الذي تم تنفيذه من خلال برنامج Java. واحد هو extclassloader. يتم استخدام هذا classloader لتحميل API Java Extension ، أي الفئة في /lib /ext ، والآخر هو AppClassloader. يتم استخدام هذا classloader لتحميل الفصل في دليل إعداد ClassPath على جهاز المستخدم. عادةً ، دون تحديد جهاز تحميل classloader ، يتم تحميل الفصول المخصصة للمبرمج بواسطة جهاز التحميل.
عند تشغيل برنامج ، يبدأ JVM ويدير bootstrap classloader. يقوم ClassLoader بتحميل API Java Core (يتم تحميل extClassloader و AppClassloader أيضًا في هذا الوقت) ، ثم يقوم باستدعاء extClassloader لتحميل واجهة برمجة تطبيقات الامتداد ، وأخيراً يقوم AppClassloader بتحميل الفصل المحدد في دليل ClassPath. هذه هي عملية التحميل الأساسية للبرنامج.
يشرح ما ورد أعلاه باختصار دور charloader وعملية التحميل الأساسية. بعد ذلك ، سنشرح الطريقة التي يتم بها تحميل ClassLoader. هنا علينا أن نتحدث عن استخدام وضع المندوب الأصل لتحميل الفصل.
يجب أن يرث كل فئة ClassLoader مخصصة مرحلة فئة مجردة ، وسيكون لكل فئة Classloader أداة تحميل من الوالدين. يمكننا أن نرى أن هناك طريقة getParent () في فئة الفئة التجريدية ، والتي يتم استخدامها لإرجاع الوالد الخاص بـ ClassLoader الحالي. لاحظ أن هذا الوالد لا يشير إلى الفئة الموروثة ، ولكن محلّل Classload المحدد عند إنشاء جهاز تحميل classloader. إذا كان هذا الوالد فارغًا ، فإن الوالد الافتراضي لـ ClassLoader هو محمل ClassLoader Bootstrap. ما هو استخدام هذا الوالد؟
يمكننا النظر في هذا الموقف. لنفترض أننا قمنا بتخصيص ClientDefClassloader ونحن نستخدم هذا classloader المخصص لتحميل java.lang.string ، ثم سيتم تحميل السلسلة بواسطة هذا classloader؟ في الواقع ، لا يتم تحميل فئة java.lang.string بواسطة clientDefClassloader ، ولكن يتم تحميلها بواسطة bootstrap classloader. لماذا هذا يحدث؟ في الواقع ، هذا هو السبب في وضع المندوب الأصل ، لأنه قبل أن يقوم أي فئة Classloader بتحميل فئة ، فإنه سيقوم أولاً بتفويض جهاز تحميل الصنف والوالد. سيتم تحميله فقط بنفسه بعد أن لا يمكن تحميل جهاز تحميل الصلابة الأب بنجاح. في المثال أعلاه ، نظرًا لأن java.lang.string عبارة عن فئة تنتمي إلى API Java Core ، لذلك عند استخدام ClientDefClassloader لتحميله ، ستقوم جهاز تحميل Classloader أولاً بتفويض صنف الأب إلى التحميل. كما ذكر أعلاه ، عندما يكون الوالد من ClassLoader فارغًا ، يكون الوالد لـ ClassLoader هو أداة تحميل فئة Bootstrap ، لذلك في المستوى الأعلى من charloader هو محمل فئة bootstrap ، لذلك ينفوض أخيرًا إلى bootstrap عند وجود charloader ، سيعود جهاز تحميل فئة bootstrap إلى فئة السلسلة.
دعونا نلقي نظرة على قطعة من الكود المصدر في classloader:
فئة متزامنة محمية LOADCLASS (اسم السلسلة ، حل منطقي) يلقي classnotfoundException {// أولاً تحقق مما إذا كانت الفئة المحددة بواسطة الاسم يتم تحميلها c = findloadedClass (name) ؛ if (c == null) {try {if (parent! = null) {// إذا لم يكن الوالد فارغًا ، اتصل بـ parent's loadclass to load = parent.loadClass (name ، false) ؛ } else {// parent is null ، call bootstrapClassLoader لتحميل c = findbootsstrapclass0 (name) ؛ }} catch (classnotfoundException e) {// إذا كان التحميل لا يزال غير ناجح ، اتصل بـ findClass لتحميل c = findClass (name) ؛ }} if (حل) {solveClass (c) ؛ } return c ؛ } من الكود أعلاه ، يمكننا أن نرى أن العملية العامة لتحميل الفصل هي نفس المثال الذي قدمته من قبل. عندما نريد تنفيذ فئة مخصصة ، نحتاج فقط إلى تنفيذ طريقة FindClass.
لماذا تستخدم نموذج تفويض الوالدين هذا؟
السبب الأول هو أن هذا يمكن أن يتجنب التحميل المتكرر. عندما يقوم الأب بتحميل الفصل ، ليست هناك حاجة لمدير رئة الطفل لتحميله مرة أخرى.
السبب الثاني هو النظر في العوامل الأمنية . دعونا نتخيل أنه إذا لم نستخدم وضع المندوب هذا ، فيمكننا استبدال الأنواع المحددة ديناميكيًا في API Java Core في أي وقت ، مما سيشكل مخاطر أمان كبيرة جدًا. يمكن أن تتجنب طريقة مندوب الأصل هذا الموقف ، لأن السلسلة تم تحميلها بالفعل عند بدء التشغيل ، وبالتالي لا يمكن للفئة المعرفة من قبل المستخدم تحميل جهاز تحميل فئة مخصص.
ما سبق هو مقدمة موجزة لآلية التحميل لـ ClassLoader . بعد ذلك ، يجب أن أشرح فئة أخرى تتعلق بـ ClassLoader ، أي فئة الفصل. في نهاية المطاف ، سيتم الرجوع إلى كل ملف فئة تم تحميله بواسطة ClassLoader من قبل المبرمج كمثيل لفئة الفصل. يمكننا علاج الفصل الدراسي كقالب للفئة العادية. يولد JVM مثيلات مقابلة بناءً على هذا القالب ويتم استخدامه أخيرًا من قبل المبرمج.
نرى أن هناك طريقة ثابتة في الفصل الدراسي. هذه الطريقة هي نفس طريقة LoadClass في ClassLoader. يتم استخدامه لتحميل الفئة ، ولكن الاثنين لهما وظائف مختلفة.
فئة <؟> loadClass (اسم السلسلة)
فئة <؟> loadclass (اسم السلسلة ، حل منطقي)
نرى إعلانات الطريقة أعلاه. يتم استخدام المعلمة الثانية للطريقة الثانية لتعيين ما إذا كنت تريد توصيل الفصل عند تحميل الفصل. إذا كان صحيحًا ، فسيتم توصيله ، وإلا فلن يتم توصيله.
الحديث عن الاتصال ، يجب أن أشرح ذلك هنا. عند تحميل فئة بواسطة JVM ، من الضروري المرور عبر ثلاث خطوات: التحميل والتوصيل والتهيئة. التحميل يعني العثور على ملف الفئة المقابل ، وقراءته في JVM ، وتهيئته ، يجب مناقشته ، أهم شيء هو التحدث عن الاتصال.
يتم تقسيم الاتصال إلى ثلاث خطوات. الخطوة الأولى هي التحقق مما إذا كان الفصل يفي بالمواصفات. الخطوة الثانية هي التحضير. هو تخصيص الذاكرة لمتغيرات الفئة وتعيين القيمة الأولية الافتراضية. الخطوة الثالثة هي التفسير. هذه الخطوة اختيارية. وفقًا للمعلمة الثانية لطريقة LoadClass أعلاه ، يتم تحديد ما إذا كان هناك حاجة إلى تفسير. يعتمد ما يسمى بالتفسير على تعريف كتاب "JVM المتعمق" والذي يهدف إلى العثور على الكيان المقابل بناءً على مراجع الرمز في الفصل ، ثم استبدل مرجع الرمز بمرجع مباشر. إنه عميق بعض الشيء ، هاها ، لن أشرح ذلك هنا. إذا كنت تريد معرفة المزيد ، يرجى قراءة "JVM المتعمق". هاها ، إذا واصلت شرحها خطوة بخطوة ، فلن تعرف متى سيتم الانتهاء منها.
دعنا نلقي نظرة على طريقة loadclass مع معلمتين. في وثيقة Java API ، يتم حماية تعريف هذه الطريقة ، مما يعني أن الطريقة محمية ، والطريقة التي يجب على المستخدمين استخدامها حقًا هي المعلمة واحدة. تقوم طريقة LoadClass بمعلمة واحدة بالفعل باستدعاء الطريقة مع معلمتين ، والمعلمة الثانية الافتراضية إلى FALSE. لذلك ، يمكن ملاحظة هنا أن فئة التحميل من خلال LoadClass لا يتم شرحها عند التحميل ، لذلك لن يتم تهيئة الفئة. طريقة اسم فئة الفصل هي عكس ذلك. عند التحميل باستخدام Forname ، سيتم شرح الفصل وتهيئته. يحتوي ForName أيضًا على إصدار آخر من الطريقة ، والتي يمكن أن تضع ما إذا كنت تريد تهيئة وضبط ClassLoader. لن أتحدث عن ذلك أكثر هنا.
أتساءل ما إذا كان شرح طريقتي التحميل واضحين بما فيه الكفاية. دعونا نعطي مثالا هنا. على سبيل المثال ، عند تحميل برنامج تشغيل JDBC ، نستخدم اسم ForName بدلاً من طريقة LoadClass لـ ClassLoader عند تحميل برامج تشغيل JDBC؟ نعلم أن سائق JDBC يمر عبر Drivermanager ويجب تسجيله في Drivermanager. إذا لم تتم تهيئة فئة السائق ، فلا يمكن تسجيلها في Drivermanager. لذلك ، يجب استخدام اسم Forname بدلاً من LoadClass.
من خلال ClassLoader ، يمكننا تخصيص محمل الفئة وتخصيص طريقة التحميل التي نحتاجها ، مثل التحميل من الشبكة ، والتحميل من تنسيقات أخرى من الملفات ، وما إلى ذلك ، في الواقع ، لا يزال هناك العديد من الأشياء التي لم يتم ذكرها في ClassLoader ، مثل بعض التطبيقات داخل Classloader ، إلخ.
من خلال هذه المقالة ، يأمل المحرر في أن يكون لدى الجميع بعض الفهم لآلية التحميل ، شكرًا لك على دعمك!