På et eller annet tidspunkt opplever utviklere frustrasjon når de arbeider med Java-klassestien. Det er ikke alltid klart hvilken klasse klasselasteren vil laste inn, spesielt når programmets klassesti blir oversvømmet med kataloger og filer. I denne artikkelen vil jeg presentere et verktøy som kan vise det absolutte banenavnet til den lastede klassefilen.
Grunnleggende om klassesti
Den virtuelle Java-maskinen (JVM) benytter en klasselaster for å laste klasser som brukes av et program etter behov. De CLASSPATH
miljøvariabel forteller klasselaster hvor du finner tredjeparts- og brukerdefinerte klasser. Du kan også spesifisere klassestien per applikasjon med -klassesti
JVM kommandolinjeargument, som overstyrer klassestien spesifisert i CLASSPATH
miljøvariabel.
Classpath-oppføringer kan være kataloger som inneholder klassefiler for klasser som ikke er i en pakke, pakkens rotkatalog for klasser i en pakke eller arkivfiler (for eksempel .zip- eller .jar-filer) som inneholder klasser. Classpath-oppføringer er kolon-separert på Unix-systemer og semikolon-separert på MS Windows-systemer.
Klasselastere er organisert i et delegasjonshierarki, hvor hver klasselaster har en overordnet klasselaster. Når en klasselaster blir bedt om å finne en klasse, delegerer den først forespørselen til sin overordnede klasselaster før den prøver å finne klassen selv. Systemklasselaster, standard klasselaster fra JDK eller JRE installert på systemet, laster tredjeparts- og brukerdefinerte klasser ved hjelp av CLASSPATH
miljøvariabel eller -klassesti
JVM kommandolinje argument. Systemklasselaster delegerer til utvidelsesklassen for å laste klasser som bruker Java Extension-mekanismen. Forlengerklasselaster delegerer til bootstrap-klasselaster (pengene stopper her!) For å laste kjernen til JDK-klassene.
Du kan utvikle spesialiserte klasselastere for å tilpasse hvordan JVM dynamisk laster inn klasser. For eksempel bruker de fleste servletmotorer en tilpasset klasselaster for å laste inn servletklasser som er endret i kataloger spesifisert i en tilpasset klassebane dynamisk.
Av spesiell betydning, og mye foruroligelse, vil klasselasteren laste klasser i den rekkefølgen de vises på klassestien. Fra og med den første klassestioppføringen besøker klasselasteren hver spesifiserte katalog eller arkivfil for å prøve å finne klassen som skal lastes inn. Den første klassen den finner med riktig navn er lastet inn, og eventuelle gjenværende klassestioppføringer blir ignorert.
Høres enkelt ut, ikke sant?
Classpath-lureri
Enten de vil innrømme det eller ikke, har både nybegynnere og veteran Java-utviklere på et eller annet tidspunkt (vanligvis i det verste øyeblikket!) Blitt lurt av den belastende klassestien. Etter hvert som antall avhengige tredjeparts- og brukerdefinerte klasser øker for et program, og klassestien blir en dumpingplass for alle tenkelige kataloger og arkivfiler, er det ikke alltid åpenbart hvilken klasse klasselasteren lastes inn først. Dette gjelder spesielt i uheldig tilfelle at klassestien inneholder dupliserte klasseoppføringer. Husk at klasselaster laster inn den første riktig navngitte klassen den finner på klassestien og "skjuler" effektivt alle andre riktig navngitte klasser med lavere prioritet.
Det er altfor lett å bli offer for denne klassebanen. Etter en lang dag med å slave over et varmt tastatur, legger du til en katalog til klassestien i et forsøk på å laste den nyeste og beste versjonen av en klasse inn i applikasjonen, mens du ikke er klar over at en annen versjon av klassen ligger i en katalog høyere prioritet i klassestien. Tok deg!
JWhich: Et enkelt klassestiverktøy
Forrangsproblemet som ligger i en flat baneerklæring er ikke unikt for Java-klassestien. For å finne en løsning på problemet krever bare at du står på skuldrene til legendariske programvaregiganter. Unix-operativsystemet hvilken
kommandoen tar et navn og viser stienavnet til filen som ville bli utført hvis navnet ble utstedt som en kommando. Det krysser i hovedsak STI
miljøvariabel for å finne den første forekomsten av kommandoen. Det høres ut som et kraftig verktøy for å administrere Java-klassestien også. Inspirert av dette begrepet begynte jeg å skrive et Java-verktøy som kunne ta et Java-klassenavn og vise det absolutte stienavnet til klassefilen som klasselasteren ville laste, som foreskrevet av klassestien.
Følgende eksempel bruk av JHvem
viser det absolutte banenavnet for den første forekomsten av com.clarkware.ejb.ShoppingCartBean
klasse som skal lastes av klasselaster, som tilfeldigvis er i en katalog:
> java JWhich com.clarkware.ejb.ShoppingCartBean Class 'com.clarkware.ejb.ShoppingCartBean' funnet i '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class'
Følgende eksempel bruk av JHvem
viser det absolutte banenavnet for den første forekomsten av javax.servlet.http.HttpServlet
klasse som skal lastes av klasselaster, som tilfeldigvis er pakket i en arkivfil:
> java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' funnet i 'file: /home/mclark/lib/servlet.jar! /javax/servlet/http/HttpServlet.class'
Hvordan JWhich fungerer
For å entydig bestemme hvilken klasse som skal lastes først i klassestien, må du komme inn i tankene til klasselasteren. Dette er ikke så vanskelig som det høres ut - du bare spør det! Den aktuelle kildekoden for JHvem
følger. For fullstendig kildekode, se Ressurser.
1: offentlig klasse JWhich {2: 3: / ** 4: * Skriver ut det absolutte stienavnet til klassefilen 5: * som inneholder det angitte klassenavnet, som foreskrevet 6: * av gjeldende klassesti. 7: * 8: * @param className Navn på klassen. 9: * / 10: offentlig statisk tomrom 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: nye JWhich (). GetClass (). GetResource (className); 20: 21: hvis (classUrl! = Null) {22: System.out.println ("\ nClass '" + className + 23: "' funnet i \ n '" + classUrl.getFile () + "'"); 24:} annet {25: System.out.println ("\ nClass '" + className + 26: "' ikke funnet i \ 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:} annet {35: System.err.println ("Bruk: java JWhich"); 36:} 37:} 38:}
Først må du massere klassenavnet litt for å få klasselaster-aksept (linje 12-16). Forhåndsbetaling av et "/" til kursnavnet instruerer klasselasteren til å matche kursnavnet ordrett innenfor klassestien, i stedet for å prøve å implisitt forberede pakkenavnet til påkallende klasse. Konverterer hver forekomst av "." til "/" formaterer klassenavnet som et gyldig URL-ressursnavn som kreves av klasselaster.
Deretter blir klasselaster forhørt (linje 18-19) for ressursen som samsvarer med riktig formatert klassenavn. Hver Klasse
objektet opprettholder en referanse til ClassLoader
objekt som lastet den, så klasselaster som lastet JHvem
klassen selv blir avhørt her. De Class.getResource ()
metoden faktisk delegerer til klasselaster som lastet klassen, returnerer en URL for lesing av klassens filressurs, eller null
hvis en klassefilressurs med det angitte klassenavnet ikke ble funnet i den gjeldende klassestien.
Til slutt vises det absolutte banenavnet til klassefilen som inneholder det spesifiserte klassenavnet, hvis det ble funnet i gjeldende klassebane (linje 21-24). Som feilsøkingshjelpemiddel, hvis klassefilen ikke ble funnet i den gjeldende klassestien, får du verdien av java.class.path
systemegenskap for å vise gjeldende klassesti (linje 24-28).
Det er lett å forestille seg hvordan denne enkle delen av koden kan påkalles i en Java-servlet ved hjelp av servlets motorens klassebane eller en Enterprise JavaBean (EJB) ved hjelp av EJB-serverens klassebane. Hvis den JHvem
klasse ble lastet av den tilpassede klasselasteren i en servletmotor, for eksempel, da ville servletmotorens klasselaster brukes til å finne klasser. Hvis servomotorens klasselaster ikke klarer å finne en klasse, vil den delegere til sin overordnede klasselaster. Generelt når JHvem
lastes av en klasselaster, kan den finne alle klassene som er lastet av klasselaster eller en hvilken som helst foreldreklasselaster.
Konklusjon
Hvis nødvendighet er mor til all oppfinnelse, er et verktøy som hjelper til med å administrere Java-klassestien, langvarig. Java-relaterte nyhetsgrupper og adresselister er fulle av spørsmål knyttet til klassestien. Vi må senke barrieren for inngang for nye utviklere, slik at vi alle kan fortsette å arbeide på høyere abstraksjonsnivå. JHvem
er et enkelt, men likevel kraftig verktøy som hjelper deg med å mestre Java-klassestien i alle miljøer.
Lær mer om dette emnet
- Få full kildekode for denne artikkelen
//images.techhive.com/downloads/idge/imported/article/jvw/2000/12/jwhich.zip
- En fullverdig versjon av JWhich, inkludert en klassesti validator, er tilgjengelig på
//www.clarkware.com/software/jwhich.zip
- Offisiell dokumentasjon for Sun JDK og hvordan den håndterer klassestien for de forskjellige offisielt støttede plattformene, er tilgjengelig på
//java.sun.com/j2se/1.3/docs/tooldocs/findingclasses.html
- For detaljer om hvordan du setter klassestien på Unix- og Windows-plattformer, se "Angi 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
- Vis alle forrige Java-tips og send inn dine egne
//www.javaworld.com/javatips/jw-javatips.index.html
- For flere Java-triks, abonner gratis på ITworld.com Java-veileder nyhetsbrev
//www.itworld.com/cgi-bin/subcontent12.cgi
- Si fra i Java Beginner-diskusjonen, moderert av JavaWorld forfatter Geoff Friesen
//www.itworld.com/jump/jw-javatip105/forums.itworld.com/webx?14@@.ee6b804/1195!skip=1125
Denne historien, "Java Tip 105: Mastering the classpath with JWhich" ble opprinnelig utgitt av JavaWorld.