På et eller andet tidspunkt oplever udviklere frustration, når de beskæftiger sig med Java-klassestien. Det er ikke altid klart, hvilken klasse klasselæsseren indlæser, især når din applikations klassesti bliver oversvømmet med mapper og filer. I denne artikel vil jeg præsentere et værktøj, der kan vise det indlæste klassefils absolutte sti.
Grundlæggende om klassesti
Den virtuelle Java-maskine (JVM) anvender en klasselæsser til at indlæse klasser, der bruges af en applikation efter behov. Det CLASSPATH
miljøvariabel fortæller klasselæsseren, hvor man finder tredjeparts- og brugerdefinerede klasser. Du kan også specificere klassestien pr. Ansøgning med -klassesti
JVM-kommandolinjeargument, som tilsidesætter klassestien, der er angivet i CLASSPATH
miljøvariabel.
Classpath-poster kan være mapper, der indeholder klassefiler for klasser, der ikke er i en pakke, pakke rodmappen til klasser i en pakke eller arkivfiler (såsom .zip- eller .jar-filer), der indeholder klasser. Classpath-poster er kolon-adskilt på Unix-system og semikolon-separeret på MS Windows-systemer.
Klasselæssere er organiseret i et delegationshierarki, hvor hver klasselæsser har en overordnet klasselæsser. Når en klasselæsser bliver bedt om at finde en klasse, delegerer den først anmodningen til sin overordnede klasselæsser, inden den forsøger at finde klassen selv. Systemklasselæsseren, standardklasselæsseren leveret af JDK eller JRE installeret på dit system, indlæser tredjeparts- og brugerdefinerede klasser ved hjælp af CLASSPATH
miljøvariabel eller -klassesti
JVM kommandolinjeargument. Systemklasselæsseren delegerer til udvidelsesklassen for at indlæse klasser, der bruger Java Extension-mekanismen. Extension class loader delegerer til bootstrap class loader (pengene stopper her!) For at indlæse JDK-klasser.
Du kan udvikle specialiserede klasselæssere til at tilpasse, hvordan JVM dynamisk indlæser klasser. For eksempel bruger de fleste servletmotorer en brugerdefineret klasselæsser til dynamisk at genindlæse servletklasser, der er ændret i mapper, der er angivet i en tilpasset klassesti.
Af særlig betydning og meget foruroligelse indlæser klasselæsseren klasser i den rækkefølge, de vises på klassestien. Startende med den første klassesti-post besøger klasselæsseren hver specificeret bibliotek eller arkivfil, der forsøger at finde den klasse, der skal indlæses. Den første klasse, den finder med det korrekte navn, indlæses, og eventuelle resterende klassebanepunkter ignoreres.
Det lyder simpelt, ikke?
Classpath trickery
Uanset om de ville indrømme det eller ej, er både begyndere og veteran Java-udviklere på et eller andet tidspunkt (normalt i det værst mulige øjeblik!) Blevet narret af den byrdefulde klassesti. Da antallet af afhængige tredjeparts- og brugerdefinerede klasser øges for en applikation, og klassestien bliver en dumpingplads for alle tænkelige biblioteker og arkivfiler, er det ikke altid indlysende, hvilken klasse klasselæsseren indlæser først. Dette gælder især i den uheldige situation, at klassestien indeholder duplikat af klasseposter. Husk, klasselæsseren indlæser den første korrekt navngivne klasse, den finder i klassestien, og "skjuler" effektivt alle andre korrekt navngivne klasser med lavere prioritet.
Det er alt for let at blive offer for denne klassesti. Efter en lang dag med at slave over et varmt tastatur, tilføjer du en mappe til klassestien i et forsøg på at få den nyeste og bedste version af en klasse indlæst i applikationen, mens du ikke er klar over, at en anden version af klassen er placeret i en mappe med højere prioritet i klassestien. Gotcha!
JWhich: Et simpelt klasseværktøjsværktøj
Forrangsproblemet, der ligger i en erklæring om flad sti, er ikke unik for Java-klassestien. At finde en løsning på problemet kræver kun, at du står på skuldrene til legendariske softwaregiganter. Unix-operativsystemets hvilken
kommando tager et navn og viser stienavnet på den fil, der ville blive udført, hvis navnet var udstedt som en kommando. Det gennemgår i det væsentlige STI
miljøvariabel for at finde den første forekomst af kommandoen. Det lyder også som et kraftfuldt værktøj til styring af Java-klassestien. Inspireret af denne opfattelse begyndte jeg at skrive et Java-værktøj, der kunne tage et Java-klassenavn og vise det absolutte stienavn på den klassefil, som klasselæsseren ville indlæse, som foreskrevet af klassestien.
Følgende eksempel brug af JWhich
viser det absolutte stinavn for den første forekomst af com.clarkware.ejb.ShoppingCartBean
klasse, der skal indlæses af klasselæsseren, som tilfældigvis er i en mappe:
> java JWhich com.clarkware.ejb.ShoppingCartBean Class 'com.clarkware.ejb.ShoppingCartBean' fundet i '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class'
Følgende eksempel brug af JWhich
viser det absolutte stinavn for den første forekomst af javax.servlet.http.HttpServlet
klasse, der skal indlæses af klasselæsseren, som tilfældigvis er pakket i en arkivfil:
> java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' fundet i 'file: /home/mclark/lib/servlet.jar! /javax/servlet/http/HttpServlet.class'
Hvordan JWhich fungerer
For entydigt at bestemme, hvilken klasse der først indlæses i klassestien, skal du komme ind i klasselæsserens sind. Dette er ikke så svært som det lyder - du skal bare spørge det! Den relevante kildekode til JWhich
følger. For den komplette kildekode, se Ressourcer.
1: offentlig klasse JWhich {2: 3: / ** 4: * Udskriver det absolutte stienavn for klassefilen 5: * indeholdende det angivne klassenavn, som foreskrevet 6: * af den aktuelle klassesti. 7: * 8: * @param className Klassens navn. 9: * / 10: offentlig statisk tomrum, som (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: ny JWhich (). GetClass (). GetResource (className); 20: 21: hvis (classUrl! = Null) {22: System.out.println ("\ nClass '" + className + 23: "' fundet i \ n '" + classUrl.getFile () + "'"); 24:} ellers {25: System.out.println ("\ nClass '" + className + 26: "' ikke fundet i \ n '" + 27: System.getProperty ("java.class.path") + "' "); 28:} 29:} 30: 31: offentlig statisk ugyldig hoved (String args []) {32: if (args.length> 0) {33: JWhich.which (args [0]); 34:} andet {35: System.err.println ("Brug: java JWhich"); 36:} 37:} 38:}
Først skal du massere klassens navn lidt for at få klasselæsseraccept (linie 12-16). Forhåndsvisning af et "/" til klassens navn instruerer klasselæsseren om at matche klassens navn ordret inden for klassestien, snarere end at prøve at implicit forberede pakkenavnet på den påkaldende klasse. Konvertering af hver forekomst af "." til "/" formaterer klassens navn som et gyldigt URL-ressourcenavn, der kræves af klasselæsseren.
Dernæst forhøres klasselæsseren (linje 18-19) for den ressource, der matcher det korrekt formaterede klassenavn. Hver Klasse
objekt opretholder en henvisning til ClassLoader
objekt, der indlæste det, så klasselæsseren, der indlæste JWhich
Klassen selv forhøres her. Det Class.getResource ()
metode delegerer faktisk til klasselæsseren, der indlæste klassen, returnerer en URL til læsning af klassens filressource eller nul
hvis en klassefilressource med det angivne klassenavn ikke kunne findes på den aktuelle klassesti.
Endelig vises det absolutte stinavn for klassefilen, der indeholder det angivne klassenavn, hvis det blev fundet på den aktuelle klassesti (linje 21-24). Som en fejlfindingshjælp, hvis klassefilen ikke blev fundet i den aktuelle klassesti, får du værdien af java.klasse.sti
systemegenskab for at vise den aktuelle klassesti (linje 24-28).
Det er let at forestille sig, hvordan denne enkle del af koden kunne påberåbes i en Java-servlet ved hjælp af servletmotorens klassesti eller en Enterprise JavaBean (EJB) ved hjælp af EJB-serverens klassesti. Hvis den JWhich
klasse blev fyldt af den brugerdefinerede klasselæsser i en servletmotor, for eksempel, så ville servletmotorklasselæsseren blive brugt til at finde klasser. Hvis servletmotorens klasselæsser ikke er i stand til at finde en klasse, delegeres den til sin overordnede klasselæsser. Generelt hvornår JWhich
indlæses af en klasselæsser, kan den finde alle klasser, der er indlæst af sin klasselæsser eller en hvilken som helst overordnet klasselæsser.
Konklusion
Hvis nødvendigheden er mor til al opfindelse, er et værktøj, der hjælper med at styre Java-klassestien, længe forsinket. Java-relaterede nyhedsgrupper og mailinglister er fyldte med spørgsmål relateret til klassestien. Vi er nødt til at sænke adgangsbarrieren for nye udviklere, så vi alle kan fortsætte med at arbejde på højere abstraktionsniveauer. JWhich
er et simpelt, men alligevel kraftfuldt værktøj, der hjælper dig med at mestre Java-klassestien i ethvert miljø.
Lær mere om dette emne
- Få den fulde kildekode til denne artikel
//images.techhive.com/downloads/idge/imported/article/jvw/2000/12/jwhich.zip
- En komplet version af JWhich, inklusive en klassesti validator, er tilgængelig på
//www.clarkware.com/software/jwhich.zip
- Officiel dokumentation til Sun JDK og hvordan den håndterer klassestien til de forskellige officielt understøttede platforme er tilgængelig på
//java.sun.com/j2se/1.3/docs/tooldocs/findingclasses.html
- For detaljer om, hvordan du indstiller klassestien på Unix- og Windows-platforme, se "Indstilling af klassestien" på:
- Unix
//java.sun.com/j2se/1.3/docs/tooldocs/solaris/classpath.html
- Windows
//java.sun.com/j2se/1.3/docs/tooldocs/win32/classpath.html
- Se alle forrige Java-tip og indsend din egen
//www.javaworld.com/javatips/jw-javatips.index.html
- For flere Java-tricks, abonner på ITworld.com's gratis Java-vejleder nyhedsbrev
//www.itworld.com/cgi-bin/subcontent12.cgi
- Tal ud i Java Beginner-diskussionen, modereret af JavaWorld forfatter Geoff Friesen
//www.itworld.com/jump/jw-javatip105/forums.itworld.com/webx?14@@.ee6b804/1195!skip=1125
Denne historie, "Java Tip 105: Mastering of the classpath with JWhich" blev oprindeligt udgivet af JavaWorld.