Apa perbedaan antara pemuat kelas konteks thread dan pemuat kelas normal?
Yaitu, jika Thread.currentThread().getContextClassLoader()
dan getClass().getClassLoader()
mengembalikan objek loader kelas yang berbeda, mana yang akan digunakan?
sumber
Apa perbedaan antara pemuat kelas konteks thread dan pemuat kelas normal?
Yaitu, jika Thread.currentThread().getContextClassLoader()
dan getClass().getClassLoader()
mengembalikan objek loader kelas yang berbeda, mana yang akan digunakan?
Setiap kelas akan menggunakan classloadernya sendiri untuk memuat kelas lain. Jadi, jika ClassA.class
referensi ClassB.class
maka ClassB
perlu berada di jalan setapak classloader ClassA
, atau orang tuanya.
Classloader konteks thread adalah classloader saat ini untuk utas saat ini. Objek dapat dibuat dari kelas di ClassLoaderC
dan kemudian diteruskan ke utas yang dimiliki oleh ClassLoaderD
. Dalam hal ini objek perlu digunakan Thread.currentThread().getContextClassLoader()
secara langsung jika ingin memuat sumber daya yang tidak tersedia pada classloadernya sendiri.
ClassB
harus di jalan setapakClassA
loader (atauClassA
orang tua loader)? MungkinkahClassA
loader overrideloadClass()
, sehingga dapat memuat dengan suksesClassB
bahkan ketikaClassB
tidak ada di classpath?ClassA.class
rujukanClassB.class
" itu?Ini tidak menjawab pertanyaan awal, tetapi karena pertanyaan itu berperingkat tinggi dan ditautkan untuk
ContextClassLoader
pertanyaan apa pun , saya pikir penting untuk menjawab pertanyaan terkait kapan pemuat kelas konteks harus digunakan. Jawaban singkat: jangan pernah gunakan pemuat kelas konteks ! Tetapi aturgetClass().getClassLoader()
ketika Anda harus memanggil metode yang tidak memilikiClassLoader
parameter.Ketika kode dari satu kelas meminta untuk memuat kelas lain, pemuat kelas yang benar untuk digunakan adalah pemuat kelas yang sama dengan kelas pemanggil (yaitu,
getClass().getClassLoader()
). Ini adalah cara kerja 99,9% dari waktu karena ini adalah apa yang JVM lakukan sendiri saat pertama kali Anda membangun sebuah instance dari kelas baru, memanggil metode statis, atau mengakses bidang statis.Ketika Anda ingin membuat kelas menggunakan refleksi (seperti ketika deserializing atau memuat kelas bernama yang dapat dikonfigurasi), perpustakaan yang melakukan refleksi harus selalu menanyakan aplikasi pemuat kelas mana yang akan digunakan, dengan menerima
ClassLoader
sebagai parameter dari aplikasi. Aplikasi (yang tahu semua kelas yang perlu dibangun) harus lulusgetClass().getClassLoader()
.Cara lain untuk mendapatkan pemuat kelas tidak benar. Jika penggunaan perpustakaan hacks seperti
Thread.getContextClassLoader()
,sun.misc.VM.latestUserDefinedLoader()
, atausun.reflect.Reflection.getCallerClass()
itu adalah bug yang disebabkan oleh kekurangan dalam API. Pada dasarnya,Thread.getContextClassLoader()
ada hanya karena siapa pun yang merancangObjectInputStream
API lupa untuk menerimaClassLoader
sebagai parameter, dan kesalahan ini telah menghantui komunitas Java hingga hari ini.Yang mengatakan, banyak banyak kelas JDK menggunakan satu dari beberapa peretasan untuk menebak beberapa loader kelas untuk digunakan. Beberapa menggunakan
ContextClassLoader
(yang gagal ketika Anda menjalankan aplikasi yang berbeda pada kumpulan utas bersama, atau ketika Anda meninggalkanContextClassLoader null
), beberapa berjalan tumpukan (yang gagal ketika penelepon langsung dari kelas itu sendiri perpustakaan), beberapa menggunakan loader sistem kelas (yang baik-baik saja, asalkan didokumentasikan hanya menggunakan kelas diCLASSPATH
) atau bootstrap kelas loader, dan beberapa menggunakan kombinasi teknik-teknik di atas yang tidak dapat diprediksi (yang hanya membuat hal-hal lebih membingungkan). Ini telah menyebabkan banyak tangisan dan kertakan gigi.Saat menggunakan API seperti itu, pertama-tama, cobalah untuk menemukan kelebihan metode yang menerima pemuat kelas sebagai parameter . Jika tidak ada metode yang masuk akal, cobalah mengatur
ContextClassLoader
sebelum panggilan API (dan mengatur ulang setelah itu):sumber
Ada artikel di javaworld.com yang menjelaskan perbedaan => ClassLoader mana yang harus Anda gunakan
(1)
(2) dari sumber yang sama:
sumber
bootstrap
pemuat kelas induk yang ditetapkan sebagai pemuat kelas konteks tetapisystem
pemuat kelas classpath anak yangThread
sedang disiapkan. TheJNDI
kelas kemudian pastikan untuk menggunakanThread.currentThread().getContextClassLoader()
untuk memuat kelas implementasi JNDI tersedia di classpath.Menambahkan ke @David Roussel jawaban, kelas dapat dimuat oleh beberapa kelas loader.
Mari kita mengerti cara kerja pemuat kelas .
Dari blog javin paul di javarevisited:
ClassLoader
mengikuti tiga prinsip.Prinsip pendelegasian
Bootstrap ClassLoader bertanggung jawab untuk memuat file kelas JDK standar dari rt.jar dan merupakan induk dari semua pemuat kelas di Jawa. Pemuat kelas bootstrap tidak memiliki orang tua.
Extension ClassLoader mendelegasikan permintaan pemuatan kelas ke induknya, Bootstrap dan jika tidak berhasil, memuat kelas dari direktori jre / lib / ext direktori atau direktori lain yang diarahkan oleh properti sistem java.ext.dirs
Pemuat kelas sistem atau Aplikasi dan bertanggung jawab untuk memuat kelas aplikasi khusus dari variabel lingkungan CLASSPATH, opsi baris -classpath atau -cp, baris atribut Path-file dari file Manifest di dalam JAR.
Pemuat kelas aplikasi adalah anak dari Extension ClassLoader dan diimplementasikan oleh
sun.misc.Launcher$AppClassLoader
kelas.CATATAN: Kecuali pemuat kelas Bootstrap , yang diimplementasikan dalam bahasa asli sebagian besar dalam bahasa C, semua pemuat kelas Java diimplementasikan menggunakan
java.lang.ClassLoader
.Prinsip Visibilitas
Prinsip Keunikan
sumber