Petua Java 105: Menguasai jalan kelas dengan JWhich

Pada satu masa atau masa yang lain, pembangun mengalami kekecewaan ketika berurusan dengan Java classpath. Tidak selalu jelas kelas mana yang dimuatkan oleh pemuat kelas, terutamanya apabila jalan kelas aplikasi anda dibanjiri dengan direktori dan fail. Dalam artikel ini, saya akan membentangkan alat yang dapat memaparkan nama jalan mutlak fail kelas yang dimuatkan.

Asas jalan kelas

Mesin maya Java (JVM) menggunakan kelas loader untuk memuat kelas yang digunakan oleh aplikasi berdasarkan keperluan. The CLASSPATHvariabel persekitaran memberitahu pemuat kelas di mana untuk mencari pihak ketiga dan kelas yang ditetapkan pengguna. Anda juga boleh menentukan classpath berdasarkan setiap aplikasi dengan -classpathargumen baris perintah JVM, yang menggantikan classpath yang ditentukan dalam CLASSPATHpemboleh ubah persekitaran.

Entri Classpath boleh berupa direktori yang mengandungi fail kelas untuk kelas yang tidak ada dalam paket, direktori root paket untuk kelas dalam pakej, atau fail arkib (seperti fail .zip atau .jar) yang mengandungi kelas. Entri Classpath dipisahkan kolon pada sistem jenis Unix dan dipisahkan titik koma pada sistem MS Windows.

Pemuat kelas disusun dalam hierarki perwakilan, dengan setiap pemuat kelas mempunyai pemuat kelas induk. Apabila pemuat kelas diminta untuk mencari kelas, pertama kali menyerahkan permintaan itu kepada pemuat kelas induknya sebelum berusaha mencari kelas itu sendiri. Pemuat kelas sistem, pemuat kelas lalai yang disediakan oleh JDK atau JRE yang dipasang pada sistem anda, memuat kelas pihak ketiga dan yang ditentukan pengguna menggunakan CLASSPATHpemboleh ubah persekitaran atau -classpathargumen baris perintah JVM. Pemuat kelas sistem mendelegasikan ke kelas peluasan untuk memuat kelas yang menggunakan mekanisme Ekstensi Java. Pemuat kelas peluasan mendelegasikan ke pemuat kelas bootstrap (wang berhenti di sini!) Untuk memuatkan kelas JDK teras.

Anda boleh mengembangkan pemuat kelas khusus untuk menyesuaikan bagaimana JVM memuat kelas secara dinamik. Sebagai contoh, kebanyakan enjin servlet menggunakan pemuat kelas khusus untuk memuat semula kelas servlet secara dinamik yang telah berubah dalam direktori yang ditentukan dalam jalan kelas khusus.

Yang sangat penting, dan sangat menyusahkan, loader kelas akan memuat kelas mengikut urutan yang mereka muncul di classpath. Bermula dengan entri classpath pertama, loader kelas mengunjungi setiap direktori atau fail arkib yang ditentukan untuk mencari kelas yang akan dimuat. Kelas pertama yang dijumpainya dengan nama yang betul dimuatkan, dan sebarang entri laluan kelas yang tersisa diabaikan.

Kedengarannya mudah, bukan?

Tipu muslihat Classpath

Sama ada mereka akan mengakuinya atau tidak, pemaju Java pemula dan veteran pada suatu ketika (biasanya pada saat terburuk!) Ditipu oleh jalan kelas yang mengerikan. Oleh kerana bilangan kelas pihak ketiga dan pengguna yang bergantung kepada pengguna meningkat, dan classpath menjadi tempat pembuangan bagi setiap fail direktori dan arkib yang difahami, tidak selalu jelas kelas mana yang dimuatkan oleh pemuat kelas terlebih dahulu. Perkara ini berlaku terutamanya dalam keadaan malang bahawa classpath mengandungi entri kelas pendua. Ingat, loader kelas memuat kelas yang dinamakan dengan betul pertama yang dijumpai di classpath dan secara berkesan "menyembunyikan" semua kelas lain yang diberi nama yang lebih baik.

Terlalu mudah untuk menjadi mangsa tipu muslihat kelas ini. Setelah berhari-hari bekerja keras menggunakan papan kekunci panas, anda menambahkan direktori ke jalan kelas dalam usaha memasukkan versi kelas terbaru dan terhebat ke dalam aplikasi, sementara tidak menyedari bahawa versi kelas yang lain terletak di direktori keutamaan yang lebih tinggi di jalan kelas. Aduh!

JWhich: Alat jalan kelas yang mudah

Masalah keutamaan yang terdapat dalam deklarasi jalan rata tidak unik untuk jalan kelas Java. Untuk mencari jalan keluar untuk masalah itu hanya memerlukan anda berdiri di atas gergasi perisian legenda. Perintah sistem operasi Unix whichmengambil nama dan memaparkan nama jalan fail yang akan dijalankan sekiranya nama tersebut dikeluarkan sebagai perintah. Ini pada dasarnya melintasi PATHpemboleh ubah persekitaran untuk mencari kejadian pertama perintah. Kedengarannya seperti alat yang hebat untuk menguruskan jalan kelas Java juga. Terinspirasi oleh gagasan itu, saya mulai menulis utiliti Java yang dapat mengambil nama kelas Java dan memaparkan nama path mutlak dari fail kelas yang dimuatkan oleh pemuat kelas, seperti yang ditentukan oleh classpath.

Contoh penggunaan berikut JWhichmenunjukkan nama jalan mutlak 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' ditemui di '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class' 

Contoh penggunaan berikut JWhichmenunjukkan nama jalan mutlak dari kejadian pertama javax.servlet.http.HttpServletkelas yang akan dimuat oleh pemuat kelas, yang kebetulan dibungkus dalam fail arkib:

 > java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' ditemui dalam 'fail: /home/mclark/lib/servlet.jar! /javax/servlet/http/HttpServlet.class' 

Bagaimana JWhich berfungsi

Untuk menentukan dengan jelas kelas mana yang akan dimuat terlebih dahulu di classpath, anda perlu masuk ke dalam minda pemuat kelas. Ini tidak sesukar yang didengar - anda hanya bertanya! Kod sumber yang berkaitan untuk JWhichdiikuti. Untuk kod sumber yang lengkap, lihat Sumber.

1: kelas awam JWhich {2: 3: / ** 4: * Mencetak nama jalan mutlak fail kelas 5: * yang mengandungi nama kelas yang ditentukan, seperti yang ditetapkan 6: * oleh classpath semasa. 7: * 8: * @param classNama Nama kelas. 9: * / 10: kekosongan statik awam 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 baru (). GetClass (). GetResource (className); 20: 21: if (classUrl! = Null) {22: System.out.println ("\ nClass '" + className + 23: "' terdapat di \ n '" + classUrl.getFile () + "'"); 24:} lain-lain {25: System.out.println ("\ nClass '" + className + 26: "' tidak dijumpai di \ n '"+ 27: System.getProperty (" java.class.path ") +" '"); 28:} 29:} 30: 31: utama kekosongan statik awam (String args []) {32: if (args.length > 0) {33: JWhich.which (args [0]); 34:} lain-lain {35: System.err.println ("Penggunaan: java JWhich"); 36:} 37:} 38:}

Pertama, anda perlu sedikit mengurut nama kelas untuk mendapatkan penerimaan pemuat kelas (baris 12-16). Menyiapkan "/" ke nama kelas memerintahkan pemuat kelas agar sesuai dengan kata nama nama kelas dalam lorong kelas, dan bukannya cuba menyisipkan secara tersirat nama pakej kelas pemanggil. Menukar setiap kejadian "." untuk "/" memformat nama kelas sebagai nama sumber URL yang sah yang diperlukan oleh pemuat kelas.

Seterusnya, pemuat kelas disoal (baris 18-19) untuk sumber yang sesuai dengan nama kelas yang diformat dengan betul. Setiap Classobjek menyimpan rujukan ke ClassLoaderobjek yang memuatnya, jadi pemuat kelas yang memuat JWhichkelas itu sendiri disoal siasat di sini. The Class.getResource()kaedah sebenarnya perwakilan untuk loader kelas yang dimuatkan kelas, kembali URL untuk membaca sumber fail kelas, atau nulljika sumber fail kelas dengan nama kelas yang dinyatakan tidak ditemui dalam classpath semasa.

Akhirnya, nama jalan mutlak fail kelas yang mengandungi nama kelas yang ditentukan akan dipaparkan, jika ia dijumpai di classpath semasa (baris 21-24). Sebagai alat bantu debug, jika fail kelas tidak dijumpai di classpath semasa, anda memperoleh nilai sifat java.class.pathsistem untuk memaparkan classpath semasa (baris 24-28).

Sangat mudah untuk membayangkan bagaimana sekeping kod sederhana ini dapat digunakan dalam servlet Java menggunakan classpath engine servlet atau Enterprise JavaBean (EJB) menggunakan classpath pelayan EJB. Sekiranya JWhichkelas dimuat oleh loader kelas khusus dalam enjin servlet, misalnya, maka pemuat kelas mesin servlet akan digunakan untuk mencari kelas. Sekiranya pemuat kelas enjin servlet tidak dapat mencari kelas, ia akan menyerahkan kepada pemuat kelas induknya. Secara umum, apabila JWhichdimuat oleh pemuat kelas, ia dapat mencari semua kelas yang dimuatkan oleh pemuat kelasnya atau pemuat kelas induk mana pun.

Kesimpulannya

Sekiranya keperluan adalah ibu dari semua penemuan, maka alat yang membantu menguruskan jalan kelas Java sudah lama tertangguh. Kumpulan berita dan senarai e-mel yang berkaitan dengan Java penuh dengan soalan yang berkaitan dengan jalan kelas. Kita perlu menurunkan penghalang masuk untuk pembangun baru supaya kita semua dapat terus bekerja pada tahap abstraksi yang lebih tinggi. JWhichadalah alat yang ringkas, namun kuat, yang akan membantu anda menguasai jalan kelas Java dalam persekitaran apa pun.

Mike Clark adalah perunding bebas untuk Clarkware Consulting, yang mengkhususkan diri dalam seni bina, reka bentuk, dan pengembangan berbasis Java menggunakan teknologi J2EE. Dia baru-baru ini menyelesaikan pengembangan dan penggunaan pelayan pertukaran XML dari perniagaan ke perniagaan (B2B) dan kini menjadi perunding untuk projek membina produk pengurusan prestasi J2EE.

Ketahui lebih lanjut mengenai 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 banyak helah Java, melanggan percuma ITworld.com yang Java Tutor surat berita

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

  • Bercakap dalam perbincangan Java Beginner, dimoderatori oleh pengarang JavaWorld Geoff Friesen

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

Kisah ini, "Petua Java 105: Menguasai jalan kelas dengan JWhich" pada asalnya diterbitkan oleh JavaWorld.