JavaRush /Java Blog /Random-TL /Paano nilo-load ang mga klase sa JVM
Aleksandr Zimin
Antas
Санкт-Петербург

Paano nilo-load ang mga klase sa JVM

Nai-publish sa grupo
Matapos makumpleto ang pinakamahirap na bahagi ng gawain ng isang programmer at naisulat ang application na "Hello World 2.0", ang natitira na lang ay i-assemble ang distribution kit at ilipat ito sa customer, o hindi bababa sa serbisyo sa pagsubok. Sa pamamahagi, lahat ay tulad ng nararapat, at kapag inilunsad namin ang aming programa, ang Java Virtual Machine ay dumating sa eksena. Hindi lihim na ang virtual machine ay nagbabasa ng mga utos na ipinakita sa mga file ng klase sa anyo ng bytecode at isinasalin ang mga ito bilang mga tagubilin sa processor. Iminumungkahi kong maunawaan nang kaunti ang tungkol sa pamamaraan ng pagpasok ng bytecode sa virtual machine.

Tagakarga ng klase

Ito ay ginagamit upang magbigay ng pinagsama-samang bytecode sa JVM, na karaniwang naka-imbak sa mga file na may extension .class, ngunit maaari ring makuha mula sa iba pang mga mapagkukunan, halimbawa, na-download sa network o binuo ng application mismo. Paano nilo-load ang mga klase sa JVM - 1Ayon sa pagtutukoy ng Java SE, upang mapatakbo ang code sa JVM, kailangan mong kumpletuhin ang tatlong hakbang:
  • naglo-load ng bytecode mula sa mga mapagkukunan at lumilikha ng isang halimbawa ng klaseClass

    kabilang dito ang paghahanap para sa hiniling na klase sa mga na-load nang mas maaga, pagkuha ng bytecode para sa pag-load at pagsuri sa kawastuhan nito, paglikha ng isang instance ng klase Class(para sa pagtatrabaho dito sa runtime), at pag-load ng mga magulang na klase. Kung ang mga klase at interface ng magulang ay hindi pa na-load, ang klase na pinag-uusapan ay ituturing na hindi na-load.

  • nagbubuklod (o nagli-link)

    Ayon sa detalye, ang yugtong ito ay nahahati sa tatlong higit pang mga yugto:

    • Pagpapatunay , ang kawastuhan ng natanggap na bytecode ay sinusuri.
    • Paghahanda , paglalaan ng RAM para sa mga static na field at pagsisimula ng mga ito gamit ang mga default na halaga (sa kasong ito, ang tahasang pagsisimula, kung mayroon man, ay nangyayari na sa yugto ng pagsisimula).
    • Resolusyon , paglutas ng mga simbolikong link ng mga uri, field at pamamaraan.
  • pagsisimula ng natanggap na bagay

    dito, hindi tulad ng mga nakaraang talata, ang lahat ay tila malinaw kung ano ang dapat mangyari. Siyempre, magiging kawili-wiling maunawaan nang eksakto kung paano ito nangyayari.

Ang lahat ng mga hakbang na ito ay isinasagawa nang sunud-sunod na may mga sumusunod na kinakailangan:
  • Dapat na ganap na na-load ang klase bago ma-link.
  • Ang isang klase ay dapat na ganap na masuri at maihanda bago ito masimulan.
  • Nagaganap ang mga error sa resolution ng link sa panahon ng pagpapatupad ng program, kahit na nakita ang mga ito sa yugto ng pag-link.
Tulad ng alam mo, ang Java ay nagpapatupad ng tamad (o tamad) na paglo-load ng mga klase. Nangangahulugan ito na ang paglo-load ng mga klase ng mga field ng sanggunian ng na-load na klase ay hindi isasagawa hanggang ang application ay makatagpo ng isang tahasang reference sa kanila. Sa madaling salita, ang paglutas ng mga simbolikong link ay opsyonal at hindi nangyayari bilang default. Gayunpaman, ang pagpapatupad ng JVM ay maaari ding gumamit ng masiglang pag-load ng klase, i.e. lahat ng simbolikong link ay dapat isaalang-alang kaagad. Para sa puntong ito nalalapat ang huling kinakailangan. Dapat ding tandaan na ang paglutas ng mga simbolikong link ay hindi nakatali sa anumang yugto ng paglo-load ng klase. Sa pangkalahatan, ang bawat isa sa mga yugtong ito ay gumagawa ng isang mahusay na pag-aaral; subukan nating alamin ang una, lalo na ang pag-load ng bytecode.

Mga Uri ng Java Loader

Mayroong tatlong karaniwang loader sa Java, na ang bawat isa ay naglo-load ng klase mula sa isang partikular na lokasyon:
  1. Ang Bootstrap ay isang pangunahing loader, na tinatawag ding Primordial ClassLoader.

    naglo-load ng mga karaniwang klase ng JDK mula sa archive ng rt.jar

  2. Extension ClassLoader – extension loader.

    naglo-load ng mga klase ng extension, na matatagpuan sa jre/lib/ext na direktoryo bilang default, ngunit maaaring itakda ng java.ext.dirs system property

  3. System ClassLoader – system loader.

    naglo-load ng mga klase ng application na tinukoy sa CLASSPATH environment variable

Gumagamit ang Java ng hierarchy ng mga class loader, kung saan ang ugat, siyempre, ang base. Susunod ay ang extension loader, at pagkatapos ay ang system loader. Naturally, ang bawat loader ay nag-iimbak ng isang pointer sa magulang upang ma-delegate ang pag-load dito kung sakaling ito mismo ay hindi magawa ito.

Abstract na klase ClassLoader

Ang bawat loader, maliban sa base one, ay isang inapo ng abstract class java.lang.ClassLoader. Halimbawa, ang pagpapatupad ng extension loader ay ang class sun.misc.Launcher$ExtClassLoader, at ang system loader ay sun.misc.Launcher$AppClassLoader. Ang base loader ay native at ang pagpapatupad nito ay kasama sa JVM. Anumang klase na umaabot java.lang.ClassLoaderay maaaring magbigay ng sarili nitong paraan ng pag-load ng mga klase na may blackjack at ang parehong mga ito. Upang gawin ito, kinakailangan na muling tukuyin ang mga kaukulang pamamaraan, na sa ngayon ay maaari ko lamang isaalang-alang nang mababaw, dahil Hindi ko naiintindihan nang detalyado ang isyung ito. Nandito na sila:
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)isa sa ilang mga pampublikong pamamaraan, na siyang entry point para sa paglo-load ng mga klase. Ang pagpapatupad nito ay bumababa sa pagtawag sa isa pang protektadong paraan loadClass(String name, boolean resolve), na kailangang ma-override. Kung titingnan mo ang Javadoc ng protektadong paraan na ito, maiintindihan mo ang isang bagay tulad ng sumusunod: dalawang parameter ang ibinibigay bilang input. Ang isa ay ang binary na pangalan ng klase (o ganap na kwalipikadong pangalan ng klase) na kailangang i-load. Ang pangalan ng klase ay tinukoy na may isang listahan ng lahat ng mga pakete. Ang pangalawang parameter ay isang flag na tumutukoy kung kinakailangan ang simbolikong resolution ng link. Bilang default ito ay false , na nangangahulugang ginagamit ang tamad na pag-load ng klase. Dagdag pa, ayon sa dokumentasyon, sa default na pagpapatupad ng pamamaraan, isang tawag ang ginawa findLoadedClass(String name), na nagsusuri kung ang klase ay na-load na dati at, kung gayon, nagbabalik ng isang reference sa klase na ito. Kung hindi, ang paraan ng paglo-load ng klase ng parent loader ay tatawagin. Kung wala sa mga loader ang makakahanap ng na-load na klase, bawat isa sa kanila, na sumusunod sa reverse order, ay susubukan na hanapin at i-load ang klase na iyon, na i-override ang findClass(String name). Ito ay tatalakayin nang mas detalyado sa kabanata na "Class Loading Scheme". At sa wakas, ang huli ngunit hindi bababa sa, pagkatapos na mai-load ang klase, depende sa flag ng paglutas , pagpapasya kung maglo-load ng mga klase sa pamamagitan ng mga simbolikong link. Ang isang malinaw na halimbawa ay ang yugto ng Resolusyon ay maaaring tawagin sa yugto ng paglo-load ng klase. Alinsunod dito, sa pamamagitan ng pagpapalawak ng klase ClassLoaderat pag-override sa mga pamamaraan nito, maaaring ipatupad ng custom loader ang sarili nitong lohika para sa paghahatid ng bytecode sa virtual machine. Sinusuportahan din ng Java ang konsepto ng isang "kasalukuyang" class loader. Ang kasalukuyang loader ay ang nag-load sa kasalukuyang executing class. Alam ng bawat klase kung aling loader ang ni-load nito, at makukuha mo ang impormasyong ito sa pamamagitan ng pagtawag sa String.class.getClassLoader(). Para sa lahat ng klase ng aplikasyon, ang "kasalukuyang" loader ay karaniwang ang sistema.

Tatlong Prinsipyo ng Pag-load ng Klase

  • Delegasyon

    Ang kahilingang i-load ang klase ay ipinapasa sa parent loader, at ang pagtatangkang i-load ang klase mismo ay gagawin lamang kung hindi mahanap at mai-load ng parent loader ang klase. Binibigyang-daan ka ng diskarteng ito na i-load ang mga klase gamit ang loader na mas malapit hangga't maaari sa base. Nakakamit nito ang maximum class visibility. Ang bawat loader ay nagpapanatili ng isang talaan ng mga klase na na-load nito, inilalagay ang mga ito sa cache nito. Ang hanay ng mga klase na ito ay tinatawag na saklaw.

  • Visibility

    Ang loader ay nakikita lamang ang "nito" na mga klase at ang mga klase ng "magulang" at walang ideya tungkol sa mga klase na ni-load ng "anak" nito.

  • Kakaiba

    Isang beses lang ma-load ang isang klase. Tinitiyak ng mekanismo ng delegasyon na ang loader na nagpasimula ng pag-load ng klase ay hindi mag-overload sa isang klase na dating na-load sa JVM.

Kaya, kapag isinusulat ang kanyang bootloader, ang isang developer ay dapat magabayan ng tatlong prinsipyong ito.

Scheme ng pag-load ng klase

Kapag may naganap na tawag para mag-load ng klase, hahanapin ang klase na ito sa cache ng mga na-load na klase ng kasalukuyang loader. Kung ang nais na klase ay hindi pa na-load dati, ang prinsipyo ng delegasyon ay naglilipat ng kontrol sa parent loader, na matatagpuan sa isang antas na mas mataas sa hierarchy. Sinusubukan din ng parent loader na hanapin ang gustong klase sa cache nito. Kung na-load na ang klase at alam ng loader ang lokasyon nito, Classibabalik ang isang object ng klase na iyon. Kung hindi, magpapatuloy ang paghahanap hanggang sa maabot nito ang base bootloader. Kung ang base loader ay walang impormasyon tungkol sa kinakailangang klase (iyon ay, hindi pa ito na-load), ang bytecode ng klase na ito ay hahanapin sa lokasyon ng mga klase na alam ng ibinigay na loader, at kung ang klase ay hindi maaaring ma-load, ang kontrol ay babalik sa child loader, na susubukan na mag-load mula sa mga pinagmulang kilala nito. Tulad ng nabanggit sa itaas, ang lokasyon ng mga klase para sa base loader ay ang rt.jar library, para sa extension loader - ang direktoryo na may jre/lib/ext extension, para sa system one - CLASSPATH, para sa user ay maaaring ibang bagay. . Kaya, ang pag-unlad ng paglo-load ng mga klase ay napupunta sa kabaligtaran na direksyon - mula sa root loader hanggang sa kasalukuyang. Kapag ang bytecode ng klase ay natagpuan, ang klase ay na-load sa JVM at isang halimbawa ng uri ay nakuha Class. Tulad ng madali mong nakikita, ang inilarawan na scheme ng pag-load ay katulad ng sa itaas na pagpapatupad ng pamamaraan loadClass(String name). Sa ibaba makikita mo ang diagram na ito sa diagram.
Paano nilo-load ang mga klase sa JVM - 2

Bilang konklusyon

Sa mga unang hakbang ng pag-aaral ng isang wika, walang partikular na pangangailangan na maunawaan kung paano nilo-load ang mga klase sa Java, ngunit ang pag-alam sa mga pangunahing prinsipyong ito ay makakatulong sa iyong maiwasan ang kawalan ng pag-asa kapag nakakaranas ng mga error tulad ng ClassNotFoundExceptiono NoClassDefFoundError. Well, o hindi bababa sa halos maunawaan kung ano ang ugat ng problema. Kaya, ang isang pagbubukod ClassNotFoundExceptionay nangyayari kapag ang isang klase ay dynamic na na-load sa panahon ng pagpapatupad ng programa, kapag ang mga loader ay hindi mahanap ang kinakailangang klase alinman sa cache o kasama ang landas ng klase. Ngunit ang error NoClassDefFoundErroray mas kritikal at nangyayari kapag ang kinakailangang klase ay magagamit sa panahon ng compilation, ngunit hindi nakikita sa panahon ng pagpapatupad ng programa. Maaaring mangyari ito kung nakalimutan ng program na isama ang library na ginagamit nito. Well, ang mismong katotohanan ng pag-unawa sa mga prinsipyo ng istraktura ng tool na ginagamit mo sa iyong trabaho (hindi kinakailangang isang malinaw at detalyadong paglulubog sa lalim nito) ay nagdaragdag ng ilang kalinawan sa pag-unawa sa mga prosesong nagaganap sa loob ng mekanismong ito, na, sa pagliko, humahantong sa tiwala na paggamit ng tool na ito.

Mga pinagmumulan

Paano Gumagana ang ClassLoader sa Java Sa pangkalahatan isang napaka-kapaki-pakinabang na mapagkukunan na may naa-access na presentasyon ng impormasyon. Naglo-load ng mga klase, ClassLoader Medyo napakahabang artikulo, ngunit may diin sa kung paano gumawa ng sarili mong pagpapatupad ng loader gamit ang parehong mga ito. ClassLoader: dynamic na paglo-load ng mga klase Sa kasamaang palad, ang mapagkukunang ito ay hindi magagamit ngayon, ngunit doon nakita ko ang pinaka-maiintindihan na diagram na may isang scheme ng pag-load ng klase, kaya hindi ko maiwasang idagdag ito. Pagtutukoy ng Java SE: Kabanata 5. Naglo-load, Nagli-link, at Nagsisimula
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION