Programmering

Java Tip 105: Mestring af klassestien med JWhich

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ø.

Mike Clark er en uafhængig konsulent for Clarkware Consulting, der specialiserer sig i Java-baseret arkitektur, design og udvikling ved hjælp af J2EE-teknologier. Han afsluttede for nylig udviklingen og implementeringen af ​​en business-to-business (B2B) XML-udvekslingsserver og er i øjeblikket konsulent for et projekt, der bygger et J2EE performance management-produkt.

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/[email protected]@.ee6b804/1195!skip=1125

Denne historie, "Java Tip 105: Mastering of the classpath with JWhich" blev oprindeligt udgivet af JavaWorld.