Tip Java 105: Menguasai jalur kelas dengan JWhich

Pada satu waktu atau lainnya, pengembang mengalami frustrasi saat berhadapan dengan jalur kelas Java. Tidak selalu jelas kelas mana yang akan dimuat oleh pemuat kelas, terutama ketika jalur kelas aplikasi Anda dibanjiri direktori dan file. Pada artikel ini, saya akan menyajikan alat yang dapat menampilkan pathname absolut dari file kelas yang dimuat.

Dasar-dasar classpath

Mesin virtual Java (JVM) menggunakan pemuat kelas untuk memuat kelas yang digunakan oleh aplikasi sesuai kebutuhan. The CLASSPATHvariabel lingkungan memberitahu loader kelas di mana untuk menemukan pihak ketiga dan kelas yang ditetapkan pengguna. Anda juga dapat menentukan jalur kelas pada basis per aplikasi dengan -classpathargumen baris perintah JVM, yang menggantikan jalur kelas yang ditentukan dalam CLASSPATHvariabel lingkungan.

Entri jalur kelas dapat berupa direktori yang berisi file kelas untuk kelas yang tidak ada dalam paket, direktori akar paket untuk kelas dalam paket, atau file arsip (seperti file .zip atau .jar) yang berisi kelas. Entri jalur kelas dipisahkan dengan titik dua pada sistem tipe Unix dan dipisahkan titik koma pada sistem MS Windows.

Pemuat kelas diatur dalam hierarki delegasi, dengan setiap pemuat kelas memiliki pemuat kelas induk. Saat pemuat kelas diminta untuk menemukan kelas, pertama-tama ia akan mendelegasikan permintaan tersebut ke pemuat kelas induknya sebelum mencoba menemukan kelas itu sendiri. Pemuat kelas sistem, pemuat kelas default yang disediakan oleh JDK atau JRE yang diinstal pada sistem Anda, memuat kelas pihak ketiga dan yang ditentukan pengguna menggunakan CLASSPATHvariabel lingkungan atau -classpathargumen baris perintah JVM. Pemuat kelas sistem mendelegasikan ke kelas ekstensi untuk memuat kelas yang menggunakan mekanisme Ekstensi Java. Pemuat kelas ekstensi mendelegasikan ke pemuat kelas bootstrap (tugas berhenti di sini!) Untuk memuat kelas inti JDK.

Anda dapat mengembangkan pemuat kelas khusus untuk menyesuaikan cara JVM memuat kelas secara dinamis. Misalnya, sebagian besar mesin servlet menggunakan loader kelas khusus untuk memuat ulang kelas servlet secara dinamis yang telah berubah dalam direktori yang ditentukan di jalur kelas khusus.

Yang sangat penting, dan banyak kekhawatiran, pemuat kelas akan memuat kelas dalam urutan kemunculannya di classpath. Dimulai dengan entri classpath pertama, pemuat kelas mengunjungi setiap direktori atau file arsip yang ditentukan untuk mencoba menemukan kelas yang akan dimuat. Kelas pertama yang ditemukannya dengan nama yang tepat akan dimuat, dan entri classpath yang tersisa akan diabaikan.

Kedengarannya sederhana, bukan?

Tipuan jalur kelas

Apakah mereka akan mengakuinya atau tidak, pengembang Java pemula dan veteran pada suatu saat (biasanya pada saat yang paling buruk!) Telah tertipu oleh classpath yang memberatkan. Karena jumlah kelas pihak ketiga dan yang ditentukan pengguna meningkat untuk suatu aplikasi, dan classpath menjadi tempat pembuangan untuk setiap direktori dan file arsip yang memungkinkan, tidak selalu jelas kelas mana yang akan dimuat pertama oleh class loader. Hal ini terutama terjadi pada kejadian yang tidak menguntungkan bahwa classpath berisi entri kelas duplikat. Ingat, pemuat kelas memuat kelas bernama benar pertama yang ditemukannya di jalur kelas dan secara efektif "menyembunyikan" semua kelas lain yang diberi nama dengan benar dengan prioritas lebih rendah.

Terlalu mudah untuk menjadi korban tipuan classpath ini. Setelah seharian bekerja keras menggunakan hot keyboard, Anda menambahkan direktori ke classpath dalam upaya untuk mendapatkan versi terbaru dan terhebat dari kelas yang dimuat ke dalam aplikasi, sementara tidak menyadari bahwa versi lain dari kelas tersebut terletak di direktori prioritas yang lebih tinggi di classpath. Kena kau!

JWhich: Alat classpath sederhana

Masalah prioritas yang melekat dalam deklarasi jalur datar tidak unik untuk jalur kelas Java. Untuk menemukan solusi untuk masalah ini hanya membutuhkan Anda berdiri di pundak raksasa perangkat lunak legendaris. Perintah sistem operasi Unix whichmengambil nama dan menampilkan nama path dari file yang akan dieksekusi jika nama tersebut dikeluarkan sebagai perintah. Ini pada dasarnya melintasi PATHvariabel lingkungan untuk menemukan kemunculan pertama perintah. Kedengarannya seperti alat yang ampuh untuk mengelola classpath Java juga. Terinspirasi oleh gagasan itu, saya mulai menulis utilitas Java yang dapat menggunakan nama kelas Java dan menampilkan nama path absolut dari file kelas yang akan dimuat oleh class loader, seperti yang ditentukan oleh classpath.

Contoh penggunaan berikut JWhichmenampilkan nama jalur absolut dari kejadian pertama com.clarkware.ejb.ShoppingCartBeankelas yang akan dimuat oleh pemuat kelas, yang kebetulan berada dalam direktori:

 > java JWhich com.clarkware.ejb.ShoppingCartBean Class 'com.clarkware.ejb.ShoppingCartBean' ditemukan di '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class' 

Contoh penggunaan berikut JWhichmenampilkan nama path absolut dari kejadian pertama javax.servlet.http.HttpServletkelas yang akan dimuat oleh loader kelas, yang kebetulan dikemas dalam file arsip:

 > java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' ditemukan di 'file: /home/mclark/lib/servlet.jar! /javax/servlet/http/HttpServlet.class' 

Bagaimana JWhich bekerja

Untuk menentukan dengan jelas kelas mana yang akan dimuat pertama kali di classpath, Anda perlu memahami pikiran class loader. Ini tidak sesulit kedengarannya - tanyakan saja! Kode sumber yang relevan untuk JWhichberikut. Untuk kode sumber lengkap, lihat Sumber.

1: public class JWhich {2: 3: / ** 4: * Mencetak nama path absolut dari file kelas 5: * berisi nama kelas yang ditentukan, seperti yang ditentukan 6: * oleh classpath saat ini. 7: * 8: * @param className Nama kelas. 9: * / 10: public static void yang (String className) {11: 12: if (! ClassName.startsWith ("/")) {13: className = "/" + className; 14:} 15: className = className.replace ('.', '/'); 16: className = className + ".class"; 17:18: java.net.URL classUrl = 19: JWhich (). GetClass (). GetResource (className) baru; 20:21: if (classUrl! = Null) {22: System.out.println ("\ nClass '" + className + 23: "' ditemukan di \ n '" + classUrl.getFile () + "'"); 24:} else {25: System.out.println ("\ nClass '" + className + 26: "' tidak ditemukan di \ n '"+ 27: System.getProperty (" java.class.path ") +" '"); 28:} 29:} 30: 31: public static void main (String args []) {32: if (args.length > 0) {33: JWhich.which (args [0]); 34:} lain {35: System.err.println ("Penggunaan: java JWhich"); 36:} 37:} 38:}

Pertama, Anda perlu sedikit memijat nama kelas agar pemuat kelas diterima (baris 12-16). Mempersiapkan "/" ke nama kelas menginstruksikan pemuat kelas untuk mencocokkan nama kelas secara verbatim di dalam classpath, daripada mencoba untuk menambahkan nama paket dari kelas pemanggilan secara implisit. Mengonversi setiap kemunculan "." untuk "/" memformat nama kelas sebagai nama sumber daya URL valid yang diperlukan oleh pemuat kelas.

Selanjutnya, pemuat kelas diinterogasi (baris 18-19) untuk sumber daya yang cocok dengan nama kelas yang diformat dengan benar. Setiap Classobjek mempertahankan referensi ke ClassLoaderobjek yang memuatnya, sehingga pemuat kelas yang memuat JWhichkelas itu sendiri diinterogasi di sini. The Class.getResource()Metode sebenarnya delegasi ke loader kelas yang dimuat kelas, kembali URL untuk membaca sumber daya file kelas, atau nulljika sumber daya file kelas dengan nama kelas yang ditentukan tidak dapat ditemukan pada classpath saat ini.

Akhirnya, nama path absolut dari file kelas yang berisi nama kelas yang ditentukan akan ditampilkan, jika ditemukan di jalur kelas saat ini (baris 21-24). Sebagai bantuan debugging, jika file kelas tidak ditemukan di jalur kelas saat ini, Anda mendapatkan nilai java.class.pathproperti sistem untuk menampilkan jalur kelas saat ini (baris 24-28).

Sangat mudah untuk membayangkan bagaimana potongan kode sederhana ini dapat dipanggil dalam servlet Java menggunakan classpath mesin servlet atau Enterprise JavaBean (EJB) menggunakan classpath server EJB. Jika JWhichkelas tersebut dimuat oleh pemuat kelas khusus di mesin servlet, misalnya, pemuat kelas mesin servlet akan digunakan untuk menemukan kelas. Jika class loader mesin servlet tidak dapat menemukan class, itu akan mendelegasikan ke class loader induknya. Secara umum, saat JWhichdimuat oleh pemuat kelas, ia dapat menemukan semua kelas yang dimuat oleh pemuat kelasnya atau pemuat kelas induk.

Kesimpulan

Jika kebutuhan adalah ibu dari semua penemuan, maka alat yang membantu mengelola jalur kelas Java sudah lama terlambat. Newsgroup dan milis yang berhubungan dengan Java penuh dengan pertanyaan yang berhubungan dengan classpath. Kami perlu menurunkan penghalang untuk masuk bagi pengembang baru sehingga kami semua dapat terus bekerja pada tingkat abstraksi yang lebih tinggi. JWhichadalah alat sederhana, namun kuat, yang akan membantu Anda menguasai jalur kelas Java di lingkungan apa pun.

Mike Clark adalah konsultan independen untuk Clarkware Consulting, yang mengkhususkan diri dalam arsitektur, desain, dan pengembangan berbasis Java menggunakan teknologi J2EE. Dia baru-baru ini menyelesaikan pengembangan dan penyebaran server pertukaran XML business-to-business (B2B) dan saat ini menjadi konsultan untuk proyek yang membangun produk manajemen kinerja J2EE.

Pelajari lebih lanjut tentang topik ini

  • Obtain the full source code for this article

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/12/jwhich.zip

  • A full-featured version of JWhich, including a classpath validator, is available at

    //www.clarkware.com/software/jwhich.zip

  • Official documentation for the Sun JDK and how it deals with the classpath for the various officially supported platforms is available at

    //java.sun.com/j2se/1.3/docs/tooldocs/findingclasses.html

  • For details on how to set the classpath on Unix and Windows platforms, see "Setting the classpath" at:
  • Unix

    //java.sun.com/j2se/1.3/docs/tooldocs/solaris/classpath.html

  • Windows

    //java.sun.com/j2se/1.3/docs/tooldocs/win32/classpath.html

  • View all previous Java Tips and submit your own

    //www.javaworld.com/javatips/jw-javatips.index.html

  • Untuk lebih trik Jawa, berlangganan gratis ITworld.com ini Java Tutor buletin

    //www.itworld.com/cgi-bin/subcontent12.cgi

  • Bicaralah dalam diskusi Pemula Java, dimoderatori oleh penulis JavaWorld Geoff Friesen

    //www.itworld.com/jump/jw-javatip105/forums.itworld.com/[email protected]@.ee6b804/1195!skip=1125

Artikel ini, "Tip Java 105: Menguasai jalur kelas dengan JWhich" awalnya diterbitkan oleh JavaWorld.