JavaRush /وبلاگ جاوا /Random-FA /چگونه کلاس ها در JVM بارگذاری می شوند
Aleksandr Zimin
مرحله
Санкт-Петербург

چگونه کلاس ها در JVM بارگذاری می شوند

در گروه منتشر شد
بعد از اینکه سخت ترین قسمت کار یک برنامه نویس تکمیل شد و برنامه «Hello World 2.0» نوشته شد، تنها چیزی که باقی می ماند مونتاژ کیت توزیع و انتقال آن به مشتری یا حداقل به سرویس تست است. در توزیع، همه چیز همانطور که باید باشد است و وقتی برنامه خود را راه اندازی می کنیم، ماشین مجازی جاوا وارد صحنه می شود. بر کسی پوشیده نیست که ماشین مجازی دستورات ارائه شده در فایل های کلاس را در قالب بایت کد می خواند و آنها را به عنوان دستورالعمل به پردازنده ترجمه می کند. من پیشنهاد می کنم کمی در مورد طرح بایت کد ورود به ماشین مجازی درک کنیم.

کلاس لودر

از آن برای تامین بایت کد کامپایل شده به JVM استفاده می شود که معمولاً در فایل هایی با پسوند ذخیره می شود .class، اما می توان آن را از منابع دیگر نیز دریافت کرد، به عنوان مثال، از طریق شبکه دانلود شود یا توسط خود برنامه تولید شود. نحوه بارگذاری کلاس ها در JVM - 1با توجه به مشخصات Java SE، برای اجرای کد در JVM، باید سه مرحله را طی کنید:
  • بارگذاری بایت کد از منابع و ایجاد نمونه ای از کلاسClass

    این شامل جستجوی کلاس درخواستی در بین کلاس‌هایی است که قبلاً بارگذاری شده‌اند، دریافت بایت کد برای بارگیری و بررسی صحت آن، ایجاد نمونه‌ای از کلاس Class(برای کار با آن در زمان اجرا)، و بارگیری کلاس‌های والد. اگر کلاس ها و رابط های والد بارگذاری نشده باشند، کلاس مورد نظر بارگذاری نشده در نظر گرفته می شود.

  • الزام آور (یا پیوند دادن)

    با توجه به مشخصات، این مرحله به سه مرحله دیگر تقسیم می شود:

    • تأیید ، صحت بایت کد دریافتی بررسی می شود.
    • آماده سازی ، تخصیص RAM برای فیلدهای استاتیک و مقداردهی اولیه آنها با مقادیر پیش فرض (در این مورد، مقداردهی اولیه صریح، در صورت وجود، قبلاً در مرحله اولیه سازی رخ می دهد).
    • وضوح ، تفکیک پیوندهای نمادین انواع، زمینه ها و روش ها.
  • مقداردهی اولیه شی دریافتی

    در اینجا، برخلاف پاراگراف های قبلی، به نظر می رسد همه چیز روشن است که چه اتفاقی باید بیفتد. البته جالب است که بفهمیم دقیقاً چگونه این اتفاق می افتد.

تمام این مراحل به صورت متوالی با الزامات زیر انجام می شود:
  • کلاس باید قبل از پیوند به طور کامل بارگذاری شود.
  • یک کلاس قبل از شروع اولیه باید به طور کامل آزمایش و آماده شود.
  • خطاهای رزولوشن پیوند در حین اجرای برنامه رخ می دهد، حتی اگر در مرحله پیوند شناسایی شده باشند.
همانطور که می دانید جاوا بارگذاری تنبل (یا تنبل) کلاس ها را پیاده سازی می کند. این بدان معنی است که بارگیری کلاس های فیلدهای مرجع کلاس بارگذاری شده تا زمانی که برنامه با ارجاع صریح به آنها مواجه نشود، انجام نخواهد شد. به عبارت دیگر، حل پیوندهای نمادین اختیاری است و به طور پیش فرض اتفاق نمی افتد. با این حال، پیاده سازی JVM همچنین می تواند از بارگذاری کلاس انرژی استفاده کند، یعنی. همه پیوندهای نمادین باید فوراً در نظر گرفته شوند. برای این نکته است که آخرین شرط اعمال می شود. همچنین شایان ذکر است که وضوح پیوندهای نمادین به هیچ مرحله ای از بارگذاری کلاس وابسته نیست. به طور کلی، هر یک از این مراحل مطالعه خوبی را انجام می دهد؛ بیایید سعی کنیم اولین مرحله، یعنی بارگذاری بایت کد را کشف کنیم.

انواع بارگذار جاوا

سه لودر استاندارد در جاوا وجود دارد که هر کدام یک کلاس را از یک مکان خاص بارگذاری می کنند:
  1. بوت استرپ یک لودر پایه است که به آن کلاس لودر اولیه نیز می گویند.

    کلاس های استاندارد JDK را از بایگانی rt.jar بارگیری می کند

  2. Extension ClassLoader – افزونه loader.

    کلاس های برنامه افزودنی را بارگیری می کند، که به طور پیش فرض در فهرست jre/lib/ext قرار دارند، اما می توانند توسط ویژگی سیستم java.ext.dirs تنظیم شوند.

  3. System ClassLoader – سیستم لودر.

    کلاس های برنامه تعریف شده در متغیر محیطی CLASSPATH را بارگیری می کند

جاوا از سلسله مراتبی از بارگذارهای کلاس استفاده می کند که البته ریشه اصلی آن پایه است. پس از آن بارگذار افزونه و سپس بارگذار سیستم می آید. به طور طبیعی، هر لودر یک اشاره گر را به والد ذخیره می کند تا در صورتی که خودش قادر به انجام این کار نباشد، بتواند بارگذاری را به آن محول کند.

کلاس انتزاعی ClassLoader

هر لودر، به استثنای پایه یک، از نوادگان کلاس انتزاعی است java.lang.ClassLoader. به عنوان مثال، پیاده سازی بارگذار پسوند کلاس است sun.misc.Launcher$ExtClassLoaderو بارگذار سیستم است sun.misc.Launcher$AppClassLoader. پایه لودر بومی است و پیاده سازی آن در JVM گنجانده شده است. هر کلاسی که گسترش یابد java.lang.ClassLoaderمی تواند راه خود را برای بارگذاری کلاس ها با بلک جک و همین موارد ارائه دهد. برای انجام این کار، لازم است روش های مربوطه را دوباره تعریف کنیم، که در حال حاضر فقط می توانم آنها را به صورت سطحی در نظر بگیرم، زیرا من این موضوع را با جزئیات متوجه نشدم. آن ها اینجا هستند:
package java.lang;
public abstract class ClassLoader {
    public Class<?> loadClass(String name);
    protected Class<?> loadClass(String name, boolean resolve);
    protected final Class<?> findLoadedClass(String name);
    public final ClassLoader getParent();
    protected Class<?> findClass(String name);
    protected final void resolveClass(Class<?> c);
}
loadClass(String name)یکی از معدود متدهای عمومی که نقطه ورود برای بارگذاری کلاس ها است. اجرای آن به فراخوانی روش محافظت شده دیگری خلاصه می شود loadClass(String name, boolean resolve)که باید نادیده گرفته شود. اگر به Javadoc این روش محافظت شده نگاه کنید، می توانید چیزی شبیه به زیر را درک کنید: دو پارامتر به عنوان ورودی ارائه می شود. یکی نام باینری کلاس (یا نام کلاس کاملاً واجد شرایط) است که باید بارگذاری شود. نام کلاس با لیستی از تمام بسته ها مشخص می شود. پارامتر دوم یک پرچم است که تعیین می کند که آیا وضوح پیوند نمادین مورد نیاز است یا خیر. به طور پیش فرض false است ، به این معنی که از بارگذاری کلاس تنبل استفاده می شود. علاوه بر این، با توجه به مستندات، در اجرای پیش‌فرض متد، یک فراخوانی برقرار می‌شود findLoadedClass(String name)که بررسی می‌کند که آیا کلاس قبلاً بارگذاری شده است یا خیر و اگر چنین است، یک مرجع به این کلاس برمی‌گرداند. در غیر این صورت، متد کلاس بارگذاری بارگذار مادر فراخوانی می شود. اگر هیچ یک از لودرها نتوانستند یک کلاس بارگذاری شده را پیدا کنند، هر یک از آنها، به ترتیب معکوس، سعی می‌کنند آن کلاس را پیدا کرده و بارگذاری کنند، و از رده خارج می‌شوند findClass(String name). این موضوع با جزئیات بیشتر در فصل "طرح بارگذاری کلاس" مورد بحث قرار خواهد گرفت. و در نهایت، در نهایت، پس از بارگیری کلاس، بسته به پرچم حل ، تصمیم گیری می شود که آیا کلاس ها از طریق پیوندهای نمادین بارگیری شوند یا خیر. یک مثال واضح این است که مرحله Resolution را می توان در مرحله بارگذاری کلاس فراخوانی کرد. بر این اساس، با گسترش کلاس ClassLoaderو نادیده گرفتن متدهای آن، لودر سفارشی می تواند منطق خود را برای تحویل بایت کد به ماشین مجازی پیاده سازی کند. جاوا همچنین از مفهوم بارگذار کلاس "جاری" پشتیبانی می کند. لودر فعلی همان لودری است که کلاس در حال اجرا را بارگذاری کرده است. هر کلاس می داند که با کدام لودر بارگذاری شده است، و شما می توانید با تماس با آن، این اطلاعات را دریافت کنید String.class.getClassLoader(). برای همه کلاس های برنامه، لودر "جاری" معمولاً یک سیستم است.

سه اصل بارگذاری کلاس

  • هیئت نمایندگی

    درخواست بارگیری کلاس به بارگذار والد ارسال می شود و تلاش برای بارگیری خود کلاس تنها در صورتی انجام می شود که بارگذار والد نتواند کلاس را پیدا و بارگذاری کند. این رویکرد به شما اجازه می دهد تا کلاس ها را با لودری که تا حد امکان نزدیک به پایه است بارگیری کنید. این به حداکثر دید کلاس می رسد. هر لودر یک رکورد از کلاس هایی که توسط خود بارگذاری شده اند را نگه می دارد و آنها را در حافظه پنهان خود قرار می دهد. به مجموعه این کلاس ها scope می گویند.

  • دید

    لودر فقط کلاس‌های «خود» و کلاس‌های «والد» را می‌بیند و هیچ ایده‌ای درباره کلاس‌هایی که توسط «فرزند» بارگیری شده‌اند ندارد.

  • منحصر به فرد بودن

    یک کلاس فقط یک بار می تواند بارگذاری شود. مکانیسم تفویض اطمینان حاصل می کند که بارگیری که بارگذاری کلاس را آغاز می کند، کلاسی را که قبلاً در JVM بارگذاری شده بود بارگذاری نمی کند.

بنابراین، هنگام نوشتن بوت لودر خود، یک توسعه دهنده باید با این سه اصل هدایت شود.

طرح بارگذاری کلاس

هنگامی که یک فراخوان برای بارگیری یک کلاس اتفاق می افتد، این کلاس در حافظه پنهان کلاس های بارگیری شده فعلی بارگیری می شود. اگر کلاس مورد نظر قبلا بارگذاری نشده باشد، اصل تفویض اختیار، کنترل را به بارگذار والد که یک سطح بالاتر در سلسله مراتب قرار دارد، منتقل می کند. بارگذار والد نیز سعی می کند کلاس مورد نظر را در حافظه پنهان خود پیدا کند. اگر کلاس قبلاً بارگذاری شده باشد و لودر مکان آن را بداند، یک شی Classاز آن کلاس برگردانده می شود. اگر نه، جستجو تا زمانی که به بوت لودر پایه برسد ادامه خواهد یافت. اگر بارگذار پایه اطلاعاتی در مورد کلاس مورد نیاز نداشته باشد (یعنی هنوز بارگذاری نشده باشد)، بایت کد این کلاس در محل کلاس هایی که لودر داده شده از آنها اطلاع دارد جستجو می شود و اگر کلاس نتواند بارگذاری شود، کنترل به بارگذار فرزند باز می گردد، که سعی می کند از منابع شناخته شده بارگیری کند. همانطور که در بالا ذکر شد، مکان کلاس‌ها برای بارگذار پایه کتابخانه rt.jar است، برای بارکننده افزونه - دایرکتوری با پسوندهای jre/lib/ext، برای سیستم یک - CLASSPATH، برای کاربر یکی می‌تواند چیزی متفاوت باشد. . بنابراین، پیشرفت کلاس های بارگیری در جهت مخالف - از بارگذار ریشه به بارگذاری فعلی می رود. وقتی بایت کد کلاس پیدا شد، کلاس در JVM بارگذاری می شود و نمونه ای از نوع به دست می آید Class. همانطور که به راحتی می توانید مشاهده کنید، طرح بارگذاری توصیف شده مشابه روش اجرای فوق است loadClass(String name). در زیر می توانید این نمودار را در نمودار مشاهده کنید.
نحوه بارگذاری کلاس ها در JVM - 2

به عنوان نتیجه گیری

در اولین مراحل یادگیری زبان، نیاز خاصی به درک نحوه بارگذاری کلاس ها در جاوا وجود ندارد، اما دانستن این اصول اولیه به شما کمک می کند در مواجهه با خطاهایی مانند ClassNotFoundExceptionیا NoClassDefFoundError. خوب، یا حداقل تقریباً درک کنید که ریشه مشکل چیست. بنابراین، یک استثنا ClassNotFoundExceptionزمانی رخ می دهد که یک کلاس در حین اجرای برنامه به صورت پویا بارگذاری شود، زمانی که لودرها نمی توانند کلاس مورد نیاز را در حافظه پنهان یا در طول مسیر کلاس پیدا کنند. اما این خطا NoClassDefFoundErrorبحرانی تر است و زمانی رخ می دهد که کلاس مورد نیاز در حین کامپایل در دسترس بود، اما در هنگام اجرای برنامه قابل مشاهده نبود. اگر برنامه فراموش کند کتابخانه ای را که استفاده می کند شامل شود، ممکن است اتفاق بیفتد. خوب، همین واقعیت درک اصول ساختار ابزاری که در کار خود استفاده می کنید (الزاماً غوطه ور شدن واضح و دقیق در اعماق آن) به درک فرآیندهای رخ داده در این مکانیسم شفافیت می بخشد، که در به نوبه خود، منجر به استفاده مطمئن از این ابزار می شود.

منابع

چگونه ClassLoader در جاوا کار می کند به طور کلی یک منبع بسیار مفید با ارائه اطلاعات در دسترس است. در حال بارگذاری کلاس ها، ClassLoader یک مقاله کاملا طولانی است، اما با تاکید بر نحوه اجرای لودر خود با همین موارد. ClassLoader: بارگذاری پویا کلاس ها متأسفانه، این منبع در حال حاضر در دسترس نیست، اما من در آنجا قابل درک ترین نمودار را با طرح بارگذاری کلاس پیدا کردم، بنابراین نمی توانم آن را اضافه نکنم. مشخصات Java SE: فصل 5. بارگذاری، پیوند دادن، و مقداردهی اولیه
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION