Saya memiliki pemuat kelas khusus sehingga aplikasi desktop secara dinamis dapat mulai memuat kelas dari AppServer yang perlu saya ajak bicara. Kami melakukan ini karena jumlah stoples yang diperlukan untuk melakukan ini konyol (jika kami ingin mengirimkannya). Kami juga memiliki masalah versi jika kami tidak memuat kelas secara dinamis saat dijalankan dari pustaka AppServer.
Sekarang, saya baru saja mengalami masalah di mana saya perlu berbicara dengan dua AppServers yang berbeda dan menemukan bahwa tergantung pada kelas mana saya memuat pertama saya mungkin rusak parah ... Apakah ada cara untuk memaksa pembongkaran kelas tanpa benar-benar membunuh JVM?
Semoga ini masuk akal
java
classloader
el_eduardo
sumber
sumber
Jawaban:
Satu-satunya cara Kelas dapat dibongkar adalah jika Classloader yang digunakan adalah sampah yang dikumpulkan. Ini berarti, referensi untuk setiap kelas tunggal dan ke classloader itu sendiri harus sesuai dengan yang dodo.
Salah satu solusi yang mungkin untuk masalah Anda adalah memiliki Classloader untuk setiap file jar, dan Classloader untuk masing-masing AppServers yang mendelegasikan pemuatan kelas yang sebenarnya ke classloader Jar tertentu. Dengan begitu, Anda bisa mengarahkan ke berbagai versi file jar untuk setiap server Aplikasi.
Ini bukan hal sepele. Platform OSGi berusaha melakukan ini, karena setiap bundel memiliki classloader yang berbeda dan dependensi diselesaikan oleh platform. Mungkin solusi yang baik adalah dengan melihatnya.
Jika Anda tidak ingin menggunakan OSGI, satu kemungkinan implementasi bisa menggunakan satu instance dari JarClassloader kelas untuk setiap file JAR.
Dan buat kelas MultiClassloader baru yang memperluas Classloader. Kelas ini secara internal akan memiliki array (atau Daftar) dari JarClassloaders, dan dalam metode defineClass () akan beralih melalui semua classloader internal sampai definisi dapat ditemukan, atau NoClassDefFoundException dilemparkan. Beberapa metode pengakses dapat disediakan untuk menambahkan JarClassloader baru ke kelas. Ada beberapa kemungkinan implementasi di internet untuk MultiClassLoader, jadi Anda bahkan mungkin tidak perlu menulis sendiri.
Jika Anda menginstal MultiClassloader untuk setiap koneksi ke server, pada prinsipnya setiap server mungkin menggunakan versi berbeda dari kelas yang sama.
Saya telah menggunakan ide MultiClassloader dalam sebuah proyek, di mana kelas yang berisi skrip yang ditentukan pengguna harus dimuat dan dibongkar dari memori dan itu bekerja dengan cukup baik.
sumber
Ya ada cara untuk memuat kelas dan "membongkar" mereka nanti. Caranya adalah dengan mengimplementasikan classloader Anda sendiri yang berada di antara loader kelas tinggi (System class loader) dan pemuat kelas dari server aplikasi, dan berharap bahwa pemuat kelas server aplikasi tidak mendelegasikan pemuatan kelas ke pemuat atas. .
Kelas didefinisikan oleh paketnya, namanya, dan kelas loader yang awalnya dimuat. Program classloader "proxy" yang merupakan yang pertama kali dimuat saat memulai JVM. Alur kerja:
java.x
dansun.x
ke classloader sistem (ini tidak boleh dimuat melalui classloader lain selain classloader sistem).Dilakukan di sana seharusnya tidak datang ClassCastException atau LinkageError dll.
Untuk informasi lebih lanjut tentang hierarki pemuat kelas (ya, itulah yang Anda terapkan di sini; -) lihat "Pemrograman Java Berbasis Server" oleh Ted Neward - buku itu membantu saya menerapkan sesuatu yang sangat mirip dengan yang Anda inginkan.
sumber
ClassLoader
per kelas agak terlalu banyak, satuClassLoader
per JAR masuk akal. Bisa lebih spesifik tentang bagaimana memaksa unggahan kelas dalam skema yang diusulkan? Misalnya bagaimana saya bisa menjamin, bahwa instance kelas yang dimuat oleh ClassLoaderA tidak dirujuk oleh instance yang dimuat oleh ClassLoaderB?Saya menulis classloader kustom, dari mana dimungkinkan untuk membongkar kelas individu tanpa GCing classloader. Jar Class Loader
sumber
JarClassLoader
untuk setiap file jar yang Anda muat, Anda dapat memanggilnyagetLoadedClasses()
, lalu beralih ke masing-masing dan bongkar.Classloader bisa menjadi masalah rumit. Anda terutama dapat mengalami masalah jika Anda menggunakan beberapa classloader dan tidak memiliki interaksinya yang jelas dan ketat. Saya pikir untuk benar-benar dapat membongkar sebuah kelas, Anda harus menghapus semua referensi ke setiap kelas (dan contoh mereka) yang Anda coba bongkar.
Kebanyakan orang perlu melakukan hal semacam ini pada akhirnya menggunakan OSGi . OSGi sangat kuat dan sangat ringan dan mudah digunakan,
sumber
Anda dapat membongkar ClassLoader tetapi Anda tidak dapat membongkar kelas tertentu. Lebih khusus Anda tidak dapat membongkar kelas yang dibuat di ClassLoader yang tidak di bawah kendali Anda.
Jika memungkinkan, saya sarankan menggunakan ClassLoader Anda sendiri sehingga Anda dapat membongkar.
sumber
Kelas memiliki referensi kuat implisit untuk instance ClassLoader mereka, dan sebaliknya. Mereka adalah sampah yang dikumpulkan seperti benda Jawa. Tanpa menekan antarmuka alat atau yang serupa, Anda tidak dapat menghapus kelas individu.
Seperti biasa Anda bisa mendapatkan kebocoran memori. Referensi kuat ke salah satu kelas atau pemuat kelas Anda akan membocorkan semuanya. Ini terjadi dengan implementasi Sun dari ThreadLocal, java.sql.DriverManager dan java.beans, misalnya.
sumber
Jika Anda menonton langsung jika kelas pembongkaran bekerja di JConsole atau sesuatu, coba tambahkan juga
java.lang.System.gc()
di akhir logika pembongkaran kelas Anda. Ini secara eksplisit memicu Pengumpul Sampah.sumber