Untuk mendapatkan pemahaman yang lebih dalam tentang ClassLoader, Anda harus terlebih dahulu tahu apa yang digunakan ClassLoader. Seperti namanya, digunakan untuk memuat file kelas ke dalam JVM untuk digunakan oleh program. Kita tahu bahwa program Java dapat secara dinamis memuat definisi kelas, dan mekanisme pemuatan yang dinamis ini diimplementasikan melalui ClassLoader, sehingga Anda dapat membayangkan betapa pentingnya ClassLoader.
Setelah melihat ini, beberapa teman mungkin memikirkan pertanyaan, yaitu, karena ClassLoader digunakan untuk memuat kelas ke dalam JVM, bagaimana classloader dimuat? Bukankah itu kelas Java?
Itu benar, memang ada classloader di sini yang tidak ditulis dalam bahasa Java, tetapi merupakan bagian dari implementasi JVM. ClassLoader ini adalah bootstrap classloader (start class loader), ClassLoader ini memuat API inti Java ketika JVM berjalan untuk memenuhi kebutuhan paling dasar dari program Java, termasuk ClassLoader yang ditentukan pengguna. ClassLoader yang ditentukan pengguna di sini mengacu pada ClassLoader yang diimplementasikan melalui program JAVA. Salah satunya adalah extclassloader. ClassLoader ini digunakan untuk memuat API ekstensi Java, yaitu, kelas di /lib /ext, dan yang lainnya adalah appclassloader. ClassLoader ini digunakan untuk memuat kelas di direktori Pengaturan ClassPath pada mesin pengguna. Biasanya, tanpa menentukan classloader, kelas khusus programmer dimuat oleh classloader.
Saat menjalankan program, JVM memulai dan menjalankan Bootstrap ClassLoader. ClassLoader memuat Java Core API (ExtClassLoader dan AppClassLoader juga dimuat saat ini), kemudian memanggil ExtClassLoader untuk memuat Extension API, dan akhirnya AppClassLoader memuat kelas yang ditentukan dalam direktori ClassPath. Ini adalah proses pemuatan paling mendasar dari suatu program.
Di atas secara singkat menjelaskan peran Classloader dan proses pemuatan paling dasar. Selanjutnya, kami akan menjelaskan cara memuat classloader. Di sini kita harus berbicara tentang penggunaan mode delegasi induk untuk pemuatan kelas.
Setiap classloader kustom harus mewarisi classloader kelas abstrak, dan setiap classloader akan memiliki classloader induk. Kita dapat melihat bahwa ada metode getParent () di ClassLoader kelas abstrak, yang digunakan untuk mengembalikan induk dari ClassLoader saat ini. Perhatikan bahwa orang tua ini tidak merujuk ke kelas yang diwariskan, tetapi classloader yang ditentukan saat membuat classloader. Jika induk ini nol, maka induk default dari classloader adalah bootstrap classloader. Apa gunanya orang tua ini?
Kita dapat mempertimbangkan situasi ini. Misalkan kami telah menyesuaikan clientDefclassLoader dan kami menggunakan classloader khusus ini untuk memuat java.lang.string, lalu akan string akan dimuat oleh classloader ini? Bahkan, kelas java.lang.string tidak dimuat oleh clientDefclassLoader, tetapi dimuat oleh bootstrap classloader. Mengapa ini terjadi? Bahkan, ini adalah alasan untuk mode delegasi induk, karena sebelum classloader kustom memuat kelas, ia pertama -tama akan mendelegasikan classloader ayahnya untuk dimuat. Itu hanya akan dimuat dengan sendirinya setelah classloader ayah tidak dapat dimuat dengan sukses. Dalam contoh di atas, karena java.lang.string adalah kelas milik Java Core API, jadi ketika menggunakan ClientDefClassLoader untuk memuatnya, ClassLoader pertama -tama akan mendelegasikan Father ClassLoader untuk memuat. Seperti disebutkan di atas, ketika induk dari ClassLoader adalah NULL, induk dari ClassLoader adalah Bootstrap ClassLoader, jadi pada tingkat atas ClassLoader adalah Bootstrap ClassLoader, jadi akhirnya mendelegasikan ke bootstrap ketika ClassLoader hadir, Bootstrap ClassLoader akan mengembalikan kelas String.
Mari kita lihat sepotong kode sumber di ClassLoader:
Kelas Sinkronisasi yang Dilindungi LoadClass (Nama String, Boolean Resolve) Melempar ClassNotFoundException {// Pertama periksa apakah kelas yang ditentukan oleh nama tersebut dimuat kelas C = findloadedClass (name); if (c == null) {coba {if (parent! = null) {// Jika induk tidak null, hubungi orangtua LoadClass ke Load = Parent.LoadClass (name, false); } else {// induk adalah null, call bootstrapclassloader untuk memuat c = findbootstrapclass0 (name); }} catch (ClassNotFoundException e) {// Jika pemuatan masih belum berhasil, hubungi FindClass Anda sendiri untuk memuat c = findClass (name); }} if (resolve) {resolveClass (c); } return c; } Dari kode di atas, kita dapat melihat bahwa proses umum memuat kelas sama dengan contoh yang saya berikan sebelumnya. Ketika kami ingin mengimplementasikan kelas khusus, kami hanya perlu mengimplementasikan metode FindClass.
Mengapa menggunakan model delegasi orang tua ini?
Alasan pertama adalah karena ini dapat menghindari pemuatan berulang. Ketika sang ayah telah memuat kelas, tidak perlu bagi classloader anak untuk memuatnya lagi.
Alasan kedua adalah untuk mempertimbangkan faktor keamanan . Mari kita bayangkan bahwa jika kita tidak menggunakan mode delegasi ini, kita dapat secara dinamis mengganti tipe yang ditentukan dalam Java Core API kapan saja, yang akan menimbulkan risiko keamanan yang sangat besar. Metode delegasi induk dapat menghindari situasi ini, karena string sudah dimuat saat startup, sehingga kelas yang ditentukan pengguna tidak dapat memuat classloader kustom.
Di atas adalah pengantar singkat untuk mekanisme pemuatan ClassLoader . Selanjutnya, saya harus menjelaskan kelas lain yang terkait dengan ClassLoader, yaitu kelas kelas. Setiap file kelas yang dimuat oleh ClassLoader pada akhirnya akan dirujuk oleh programmer sebagai contoh kelas kelas. Kita dapat memperlakukan kelas kelas sebagai templat kelas biasa. JVM menghasilkan contoh yang sesuai berdasarkan templat ini dan akhirnya digunakan oleh programmer.
Kami melihat bahwa ada forname metode statis di kelas kelas. Metode ini sama dengan metode LoadClass di ClassLoader. Ini digunakan untuk memuat kelas, tetapi keduanya memiliki fungsi yang berbeda.
Kelas <?> LoadClass (nama string)
Class <?> LoadClass (nama string, boolean resolve)
Kami melihat dua deklarasi metode di atas. Parameter kedua dari metode kedua digunakan untuk mengatur apakah akan menghubungkan kelas saat memuat kelas. Jika benar, itu akan terhubung, jika tidak itu tidak akan terhubung.
Berbicara tentang koneksi, saya harus menjelaskannya di sini. Saat memuat kelas berdasarkan JVM, perlu melalui tiga langkah: memuat, menghubungkan, dan menginisialisasi. Memuat berarti menemukan file kelas yang sesuai, membacanya ke dalam JVM, dan menginisialisasi itu perlu dibahas, yang paling penting adalah berbicara tentang koneksi.
Koneksi dibagi menjadi tiga langkah. Langkah pertama adalah memverifikasi apakah kelas memenuhi spesifikasi. Langkah kedua adalah persiapan. Ini untuk mengalokasikan memori untuk variabel kelas dan mengatur nilai awal default. Langkah ketiga adalah penjelasan. Langkah ini opsional. Menurut parameter kedua dari metode LoadClass di atas, ditentukan apakah diperlukan penjelasan. Penjelasan yang disebut didasarkan pada definisi buku "JVM mendalam" yang menemukan entitas yang sesuai berdasarkan referensi simbol di kelas, dan kemudian mengganti referensi simbol dengan referensi langsung. Agak mendalam, haha, saya tidak akan menjelaskannya di sini. Jika Anda ingin tahu lebih banyak, silakan baca "JVM yang mendalam". Haha, jika Anda terus menjelaskannya langkah demi langkah, Anda tidak akan tahu kapan itu akan selesai.
Mari kita lihat metode LoadClass dengan dua parameter. Dalam dokumen API Java, definisi metode ini dilindungi, yang berarti bahwa metode ini dilindungi, dan metode yang harus benar -benar digunakan pengguna adalah yang memiliki satu parameter. Metode LoadClass dari satu parameter sebenarnya memanggil metode dengan dua parameter, dan parameter kedua default ke false. Oleh karena itu, dapat dilihat di sini bahwa kelas pemuatan melalui LoadClass sebenarnya tidak dijelaskan saat memuat, sehingga kelas tidak akan diinisialisasi. Metode gabungan kelas kelas adalah sebaliknya. Saat memuat dengan forname, kelas akan dijelaskan dan diinisialisasi. Forname juga memiliki versi lain dari metode ini, yang dapat mengatur apakah akan menginisialisasi dan mengatur ClassLoader. Saya tidak akan membicarakannya lebih banyak di sini.
Saya bertanya -tanya apakah penjelasan dari dua metode pemuatan ini cukup jelas. Mari berikan contoh di sini. Misalnya, saat memuat driver JDBC , kami menggunakan forname alih -alih metode LoadClass dari ClassLoader saat memuat driver JDBC? Kita tahu bahwa driver JDBC melalui DriverManager dan harus terdaftar di DriverManager. Jika kelas driver tidak diinisialisasi, itu tidak dapat didaftarkan di DriverManager. Oleh karena itu, forname harus digunakan sebagai ganti loadclass.
Melalui ClassLoader, kami dapat menyesuaikan loader kelas dan menyesuaikan metode pemuatan yang kami butuhkan, seperti memuat dari jaringan, memuat dari format file lain, dll. Bahkan, masih ada banyak hal yang belum disebutkan di ClassLoader, seperti beberapa implementasi di dalam ClassLoader, dll.
Melalui artikel ini, editor berharap bahwa semua orang akan memiliki pemahaman tentang mekanisme ClassLoader, terima kasih atas dukungan Anda!