Kata pengantar
Setiap orang harus tahu bahwa ketika proyek Java dimulai, JVM akan menemukan metode utama, dan memuat file kelas dan file kelas dalam paket JAR yang direferensikan sesuai dengan panggilan antara objek (langkah -langkah dibagi menjadi pemuatan, verifikasi, persiapan, penguraian, inisialisasi, penggunaan dan pembongkaran). Area metode membuka memori untuk menyimpan struktur data runtime kelas (termasuk variabel statis, metode statis, kumpulan konstan, struktur kelas, dll.), Dan pada saat yang sama, objek kelas yang sesuai dihasilkan dalam tumpukan untuk menunjuk ke struktur data runtime kelas yang sesuai di area metode.
Untuk meringkas dalam kalimat paling sederhana, proses pemuatan kelas adalah bahwa JVM membaca file bytecode kelas melalui aliran IO berdasarkan jalur file kelas yang diperlukan, dan menyuntikkannya ke dalam memori melalui serangkaian langkah parsing dan inisialisasi. Loader kelas di Java meliputi: bootstrapclassloader (lapisan atas), extclassloader, appclassloader, dan classloader yang ditentukan pengguna (lapisan bawah). Untuk berbagai jenis paket JAR (atau file kelas), JVM akan memiliki berbagai jenis loader kelas untuk dimuat.
Hubungan yang sesuai adalah sebagai berikut:
BootstrapClassLoader digunakan untuk memuat kelas yang diperlukan untuk JVM yang berjalan:
Java_home/jre/lib/sumber daya. Java_home/jre/lib/jfr.jar: java_home/jre/lib/kelas
ExtClassLoader digunakan untuk memuat kelas ekstensi:
../Java/extensions: ../java_home/jre/lib/ext: ../library/java/extensions:/network/library/java/extensions: ../system/library/java/extensions: ../java
AppClassLoader digunakan untuk memuat kelas yang dibuat di bawah ClassPath dan kelas yang dirujuk dalam paket JAR dalam proyek kami.
Seluruh pemuatan kelas dimuat melalui mekanisme yang disebut delegasi induk.
Misalnya, kelas dimuat oleh loader level terendah (ClassLoader yang ditentukan pengguna). Loader ini pertama -tama akan memanggil loader level sebelumnya (AppClassLoader) untuk memuat, dan AppClassLoader akan terus diserahkan ke level atas (ExtClassLoader) untuk memuat hingga BootstrapClassLoader. Jika ClassPath dimuat oleh BootstrapClassLoader tidak dapat menemukan kelas ini, itu akan diserahkan ke loader (extclassloader) dari lapisan berikutnya untuk memuat. Jika kelas ini tidak dapat ditemukan, itu akan terus diserahkan ke lapisan berikutnya (AppClassLoader) untuk memuat. Dan seterusnya, jika ClassLoader yang ditentukan pengguna tidak dapat menemukan kelas ini, program akan melempar ClassNotFoundError.
Seluruh proses pemuatan ditampilkan sebagai berikut:
(Gambar dikutip dari: https://www.cnblogs.com/xing901022/p/4574961.html)
Pelacakan kode sumber dari sumber pemuatan kelas adalah sebagai berikut (kode sumber telah disederhanakan dengan tepat di sini). Pembaca dapat mengklik kode sumber untuk melihat:
Paket java.lang.classloader; impor ...... kelas yang dilindungi <?> LoadClass (nama string, boolean tekad) melempar ClassNotFoundException {disinkronkan (getClassLoadingLock (name)) {// Pertama, temukan dalam memori mesin virtual apakah kelas ini telah dimuat ... masalah utama dengan class lies! Lai Lai Kelas <?> C = findloadedclass (name); if (c == null) {long t0 = system.nanoTime (); Coba {if (parent! = null) {// Biarkan loader layer sebelumnya memuat pertama c = parent.loadclass (name, false); } else {c = findbootstrapclassornull (name); }} catch (classnotfoundException e) {// classnotfoundException dilemparkan jika kelas tidak ditemukan // dari class non-null class loader} if (c == null) {// kalender metode findClass yang diimplementasikan oleh loader ini untuk memuat c = findClass (name); }} if (resolve) {resolveClass (c); } return c; }}Anda dapat sepenuhnya menghargai proses mekanisme delegasi orang tua dalam kode sumber, dan tiga kalimat paling penting dari kode telah ditandai:
Jika pengguna membutuhkan loader khusus dan memuat file kelas dari jalur yang ditentukan, ia perlu mewarisi metode ClassLoader dan mengimplementasikan metode FindClass (String Name). Sebagai contoh:
Paket com.linuxidc.utils; import java.io.bytearrayoutputStream; import java.io.fileInputStream; import java.io.ioException; import java.io.inputStream; kelas publik ServiceClassloader memperluas classloader {private string classpath; Public ServiceClassLoader (String classPath) {this.classpath = classPath; } /*** Tulis ulang metode FindClass dari kelas induk. LoadClass dari kelas induk akan memanggil metode ini */ @Override Protected Class <?> FindClass (nama string) melempar ClassNotFoundException {class <?> C = null; byte [] classData = getClassData (name); if (classData! = null) {c = Defineclass (name, classData, 0, classData.length); } else {lempar classnotfoundException baru (); } return c; } // Baca file kelas melalui aliran IO dan ubah menjadi byte array private byte [] getClassData (name string) {string path = classpath + "/" + name.replace ('.', '/') + ".Class"; Inputstream istream = null; BytearrayoutputStream bytearrayoutputStream = new bytearrayoutputStream (); coba {istream = new fileInputStream (path); byte [] buffer = byte baru [1024]; int temp = 0; while ((temp = istream.read (buffer))! =-1) {bytearrayoutputStream.write (buffer, 0, temp); } if (bytearrayoutputStream! = null) {return bytearrayoutputStream.tobyteArray (); }} catch (Exception e) {e.printstacktrace (); } akhirnya {coba {if (istream! = null) {istream.close (); }} catch (ioException e) {E.PrintStackTrace (); } coba {if (bytearrayoutputStream! = null) {bytearrayoutputStream.close (); }} catch (ioException e) {E.PrintStackTrace (); }} return null; }}Kode untuk menggunakan class loader adalah sebagai berikut:
ServiceClassLoader serviceClassLoader = new serviceClassLoader ("c:/myclass"); czlass <?> C = serviceClassLoader.loadClass ("com.linuxidc.service.myclass");Jika Anda menggunakan objek ServiceClassLoader yang sama untuk memuat file kelas yang sama beberapa kali, objek kelas setelah setiap beban adalah sama! Namun, jika ClassLoader kustom baru yang berbeda memuat file kelas yang sama, objek kelas yang berbeda akan dikembalikan setiap kali.
Catatan: File kelas yang ingin Anda muat tidak dapat ditempatkan di direktori ClassPath dan subdirektori apa pun, jika tidak, itu akan dimuat terlebih dahulu oleh AppClassLoader (ini karena pemuatan kelas mengadopsi mekanisme delegasi induk, dan AppClassLoader dapat memuat semua file kelas di bawah ClassPath). Setiap kali, appclassloader yang sama dimuat, sehingga akan ada masalah caching kelas.
Ini memecahkan masalah menggunakan refleksi secara langsung ketika kelas JVM memuat.
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap konten artikel ini memiliki nilai referensi tertentu untuk studi atau pekerjaan semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.