Ada dua jenis classload di Java, satu ditentukan pengguna, dan yang lainnya adalah bootstrap class loader yang dibangun di JVM.
Ada tiga jenis loader kelas yang dibangun di JVM, yaitu Bootstrap ClassLoader, Extension ClassLoader (mis. ExtclassLoader), dan System ClassLoader (mis. AppClassLoader).
Saya tidak akan berbicara tentang delegasi orang tua ketika JVM dimuat, ada banyak artikel tentang javaeye yang diperkenalkan ...
Anda dapat melihat konstruktor mereka secara terpisah, di mana ClassLoader Bootstrap ditulis dalam c.
java.lang.classloader
ClassLoader (ClassLoader) {SecurityManager Security = System.GetSecurityManager (); true; diinisialisasi = true;}
Konstruktor ini memiliki dua parameter dan tidak ada konstruktor. Konstruktor dengan parameter lewat di loader induk dari class loader ini, sedangkan konstruktor tanpa parameter akan memperlakukan loader kelas yang dikembalikan oleh GetSystemClassLoader () sebagai orangtua loader sendiri
Public ClassLoader GetSystemClassLoader () {// Loader kelas yang dikembalikan ditugaskan InitSystemClassLoader (); CCL = GetCallerClassLoader (); if (! sclset) {if (scl! = null) lempar new ilegalstateException ("doa rekursif"); oops = null; // nilainya ditetapkan scl = l.getClassLoader (); ................................ .... .....................................}} sclset = true; Loader kelas induk di sini adalah SCL, yang diperoleh oleh l.getClassLoader (), getClassLoader (), dan kemudian lihat kode sumber peluncur:
Private Static Launcher Launcher = New Launcher ();
peluncur statis public getLauncher () {return peluncur; ); AppClassLoader, artinya, GetSystemClassLoader mengembalikan appClassLoader loader = appclassLoader.getAppClassLoader (extcl); Thread, untuk mencegah kebingungan yang disebabkan oleh classload di Multithreads (saya mengerti ini sendiri, haha) // Atur class class loader untuk utas utama. .................................................. ................................................ .. ..............} / * * Mengembalikan loader kelas yang digunakan untuk meluncurkan aplikasi utama. Dari sini kita melihat bahwa pemuat induk dari AppClassLoader adalah ExtclassLoader, dan apa loader induk dari ExtClassLoader? Mari kita lihat konstruktor extclassloader:
Public ExtClassLoader (File [] Dirs) melempar IoException {super (getExtURLS (Dirs), null, factory);Loader induknya kosong, sedangkan kelas induk tingkat atasnya adalah java.lang.classloader. Ketika orang tua lewat adalah nol, ketika kita menggunakan extclassloader untuk memuat kelas, sistem akan memanggil bootstrap classloader.
Kelas Sinkronisasi yang Dilindungi <?> LoadClass (Nama String, Boolean Resolve) Melemparkan ClassNotFoundException {// Pertama, periksa apakah kelas telah dimuat kelas C = findloadedClass (name); ! = NULL) {// Panggil orang tua Loader terlebih dahulu untuk memuat. ) {// Jika masih belum ditemukan, lalu naikkan CLASS secara berurutan // untuk menemukan kelasnya.Di sini, FindbootStrapClass0 adalah untuk memanggil Bootstrap ClassLoader, loader kelas inti terbanyak, untuk memuat kelas.
Akhirnya, kita dapat melihat bahwa loader kelas yang dikembalikan oleh getSystemClassLoader () adalah appclassloader.
Analisis mekanisme classloader java
JDK Default ClassLoader
JDK menyediakan classloader berikut secara default
Bootstrp loader
Bootstrp Loader ditulis dalam bahasa C ++. JRE/Kelas.
Extclassloader
Bootstrp Loader memuat extclassloader dan menetapkan loader induk dari extclassloader ke bootstrp loader. Ini semua direktori kelas di bawah pustaka Path and Class di jalur yang ditentukan oleh variabel sistem java.ext.dirs.
AppClassLoader
Setelah bootstrp loader memuat ExtClassLoader, AppClassLoader akan dimuat, dan loader induk dari AppClassLoader ditentukan sebagai ExtClassLoader. AppClassLoader juga ditulis di Java. Ini adalah dokumen JAR, yang juga merupakan loader kelas default untuk program Java.
Singkatnya, hubungan di antara mereka dapat dijelaskan dalam gambar berikut:
Model delegasi orang tua
Pemuatan ClassLoader di Java mengadopsi mekanisme delegasi orang tua.
Saat ini, ClassLoader pertama -tama memeriksa apakah kelas ini telah dimuat dari kelas yang telah dimuat.
Setiap class loader memiliki cache pemuatan sendiri.
Ketika cache ClassLoader tidak ditemukan, loader kelas induk didelegasikan untuk memuatnya. cara ke bootstrp classloader.
Ketika semua loader kelas induk tidak dimuat, mereka dimuat oleh loader kelas saat ini dan memasukkannya ke dalam cache sendiri sehingga mereka dapat dikembalikan secara langsung saat berikutnya ada permintaan pemuatan.
Berbicara tentang ini, Anda mungkin bertanya -tanya, mengapa Java mengadopsi mekanisme delegasi seperti itu? Untuk memahami masalah ini, kami memperkenalkan konsep lain "namespace" tentang ClassLoader, yang berarti bahwa untuk menentukan kelas tertentu, Anda memerlukan nama kelas yang memenuhi syarat dan memuat kelas ini ClassLoader untuk secara bersama -sama menentukannya. Dengan kata lain, bahkan jika nama -nama yang sepenuhnya memenuhi syarat dari kedua kelas tersebut sama, karena classloader yang berbeda memuat kelas ini, maka itu adalah kelas yang berbeda dalam JVM. Setelah memahami namespace, mari kita lihat model delegasi. Setelah mengadopsi model delegasi, kemampuan interaktif dari berbagai classloader meningkat. materi program Anda ada begitu banyak loader kelas di dalamnya, sehingga kelas -kelas ini sebenarnya dapat dibagikan, yang menghindari kebingungan yang disebabkan oleh loader kelas yang berbeda setelah memuat kelas yang berbeda dengan nama yang sama.
Cara menyesuaikan classloader
Selain classloader default yang disebutkan di atas, Java juga memungkinkan aplikasi untuk menyesuaikan classloader. Kita perlu memperhatikan beberapa metode penting:
1.LoadClass Metode
Metode LoadClass menyatakan
kelas publik <?> LoadClass (nama string) melempar ClassNotFoundException
Di atas adalah deklarasi prototipe dari metode LoadClass. Mari kita lihat kode metode ini untuk melihat bagaimana itu mengimplementasikan delegasi orang tua.
Metode LoadClass mengimplementasikan
kelas publik <?> LoadClass (Name String) melempar ClassNotFoundException {return loadClass (name, false);}Dari yang di atas, kita dapat melihat bahwa metode LoadClass memanggil metode LoadCclass (Name, False), jadi mari kita lihat implementasi metode LoadClass lainnya.
Class LoadClass (nama string, boolean resolve)
Kelas Sinkronisasi yang Dilindungi <?> LoadClass (Nama String, Boolean Resolve) Melemparkan ClassNotFoundException {// Pertama, periksa apakah kelas telah dimuat kelas C = findloadedClass (name); // periksa apakah kelas telah dimuat jika (c = = null) {coba {if (induk! = null) {c = parent.loadClass (name, false); } else {c = findBootStrapClass0 (name); // Jika tidak ada class loader induk, delegasi bootstrap loader untuk memuat}} catch (classnotfoundException e) {// jika masih belum ditemukan, kemudian Invok e findclass dalam urutan // Temukan kelas. }} if (resolve) {resolveclass (c);} return c;}Dalam kode di atas, saya menambahkan komentar untuk melihat dengan jelas bagaimana mekanisme delegasi induk dari LoadClass bekerja. Satu hal yang perlu kita perhatikan di sini adalah bahwa kelas publik <?> LoadClass (Name String) melempar ClassNotFoundException tidak ditandai sebagai final, yang berarti bahwa kita dapat mengganti metode ini, yang berarti bahwa mekanisme delegasi induk dapat rusak. Selain itu, kami perhatikan bahwa ada metode FindClass di atas.
2.FindClass
Kami memeriksa kode sumber java.lang.classloader dan kami menemukan bahwa implementasi FindClass adalah sebagai berikut:
Kelas Protected <?> FindClass (Name String) Melempar ClassNotFoundException {Throw New ClassNotFoundException (name);}Kita dapat melihat bahwa implementasi default dari metode ini adalah secara langsung melempar pengecualian, tetapi pada kenyataannya, metode ini diserahkan pada aplikasi kami untuk mengganti. Implementasi spesifik tergantung pada logika implementasi Anda. Mari kita jelaskan Defineclass nanti. OK, melalui analisis di atas, kita dapat menarik kesimpulan berikut:
Ketika kita menulis classloader kita sendiri, jika kita ingin mengikuti mekanisme delegasi induk, kita hanya perlu mengganti FindClass.
3. Defineclass
Mari pertama -tama lihat kode sumber Defineclass:
Defineclass
Kelas Akhir yang Dilindungi <?> Defineclass (nama string, byte [] b, int off, int len) melempar classFormateRror {return defineclass (name, b, off, len, null);}Dari kode di atas, kita dapat melihat bahwa metode ini didefinisikan sebagai final, yang berarti bahwa metode ini tidak dapat ditimpa. File harus mematuhi definisi kelas yang ditentukan oleh spesifikasi mesin virtual Java. Metode ini akhirnya akan memanggil metode asli untuk mengimplementasikan pemuatan kelas nyata.
OK, melalui deskripsi di atas, mari kita pikirkan tentang pertanyaan berikut:
Jika kita menulis kelas Java.lang.string sendiri, bisakah kita mengganti kelas yang memanggil JDK sendiri?
Jawabannya adalah tidak. Kami tidak dapat mencapainya. Mengapa? Saya melihat banyak penjelasan online bahwa mekanisme delegasi orang tua memecahkan masalah ini, tetapi sebenarnya tidak terlalu akurat. Karena mekanisme delegasi induk dapat rusak, Anda dapat menulis classloader untuk memuat kelas java.lang.string yang Anda tulis, tetapi Anda akan menemukan bahwa itu tidak akan berhasil, khususnya karena itu untuk kelas yang dimulai dengan Java.*, JVM Implementasi telah memastikan bahwa itu harus dimuat oleh Bootstrp.
Skenario yang tidak mengikuti "mekanisme delegasi orang tua"
Di atas disebutkan bahwa mekanisme delegasi orang tua terutama untuk mewujudkan masalah interaksi kelas yang dimuat di antara classloader yang berbeda. Parent Class Loader di Java. Mari kita bicara tentang terjadinya situasi ini.
Ada standar SPI (Layanan Penyedia Layanan) di Java, yang menggunakan perpustakaan SPI, seperti JDBC, JNDI, dll. Kita semua tahu bahwa JDBC membutuhkan pengemudi yang disediakan oleh pihak ketiga, dan paket JAR driver ditempatkan dalam aplikasi kami sendiri. ClassPath, dan JDBC's API adalah bagian dari ketentuan JDK, dan telah dimuat oleh Bootstrp. Java memperkenalkan konsep pemuatan kelas utas. driver, tidak apa -apa memuat melalui loader kelas konteks utas.
Selain itu, untuk mengimplementasikan Loader OSGI kelas yang lebih fleksibel dan beberapa server aplikasi Java, ia juga merusak mekanisme delegasi induk.