Java Tip 105: Овладяване на пътя на класа с JWhich

По едно или друго време разработчиците изпитват разочарование, когато се занимават с Java classpath. Не винаги е ясно кой клас ще зареди зареждащият клас, особено когато пътят на класа на приложението ви е залят с директории и файлове. В тази статия ще представя инструмент, който може да покаже абсолютното име на пътя на заредения файл на класа.

Основи на Classpath

Виртуалната машина Java (JVM) използва зареждащ клас за зареждане на класове, използвани от приложение, според нуждите. В CLASSPATHпроменливата среда разказва клас товарач къде да намерите на трета страна и потребителски дефинирани класове. Можете също така да посочите пътя на класа за всяко приложение с -classpathаргумента на командния ред на JVM, който заменя пътя на класа, посочен в CLASSPATHпроменливата на средата.

Записите в Classpath могат да бъдат директории, които съдържат файлове с класове за класове, които не са в пакет, коренна директория на пакета за класове в пакет или архивни файлове (като .zip или .jar файлове), които съдържат класове. Записите в Classpath са разделени с двоеточие в системи от тип Unix и точки с точка и запетая в системи MS Windows.

Зареждачите на класове са организирани в йерархия на делегиране, като всеки товарач на клас има родител на родителски клас. Когато се поиска от зареждащ клас да намери клас, той първо делегира заявката на своя родителски клас, преди да се опита да намери самия клас. Зареждачът на системния клас, зареждачът по подразбиране, предоставен от JDK или JRE, инсталиран на вашата система, зарежда класове на трети страни и дефинирани от потребителя с помощта на CLASSPATHпроменливата на средата или -classpathаргумента на командния ред на JVM. Устройството за зареждане на системен клас делегира в разширения клас, за да зареди класове, които използват механизма Java Extension. Устройството за зареждане на разширения клас делегира в зареждащия клас на bootstrap (парите спират тук!), За да зареди основните JDK класове.

Можете да разработите специализирани товарачи на класове, за да персонализирате как JVM динамично зарежда класове. Например, повечето двигатели на сървлети използват зареждащ потребителски клас за динамично презареждане на класовете на сървлети, които са се променили в директории, посочени в персонализиран път на класа.

От особено значение и голямо учудване, зареждащият клас ще зарежда класовете в реда, в който се появяват в пътя на класа. Започвайки с първия запис на classpath, зареждащият клас посещава всяка посочена директория или архивен файл, опитвайки се да намери класа за зареждане. Първият клас, който намери с правилното име, се зарежда и всички останали записи на пътя на класа се игнорират.

Звучи просто, нали?

Измама на Classpath

Независимо дали биха признали това или не, начинаещи и ветерани Java разработчици в даден момент (обикновено във възможно най-лошия момент!) Бяха подмамени от обременителната пътека на класа. Тъй като броят на зависимите трети и дефинирани от потребителя класове се увеличава за дадено приложение и пътят на класа се превръща в сметище за всяка възможна директория и архивен файл, не винаги е очевидно кой клас зареждащият клас ще зареди първо. Това е особено вярно в злополучното събитие, че пътят на класа съдържа дублирани записи на класа. Не забравяйте, че зареждащият клас зарежда първия правилно именуван клас, който намира в пътя на класа, и ефективно „скрива“ всички други правилно именувани класове с по-нисък приоритет.

Твърде лесно е да станете жертва на този трик на класа. След дълъг ден на робство над гореща клавиатура, добавяте директория към пътя на класа в опит да получите най-новата и най-добрата версия на клас, зареден в приложението, като същевременно не знаете, че друга версия на класа се намира в директория на по-висок приоритет в пътя на класа. Хванах те!

JWhich: Прост инструмент за пътеки на класа

Проблемът с приоритета, присъщ на декларацията за плосък път, не е уникален за Java classpath. За да намерите решение на проблема, е необходимо само да застанете на раменете на легендарните софтуерни гиганти. Командата на операционната система Unix whichвзема име и показва името на пътя на файла, който ще бъде изпълнен, ако името е издадено като команда. По същество той обхожда PATHпроменливата на средата, за да намери първото появяване на командата. Това също звучи като мощен инструмент за управление на пътя на класа на Java. Вдъхновен от тази идея, се заех с написването на помощна програма на Java, която може да вземе име на клас на Java и да покаже абсолютното име на пътя на файла на класа, който зареждащият клас би заредил, както е предписано от classpath.

Следващият пример за използване на JWhichпоказва абсолютното име на пътя на първото появяване на com.clarkware.ejb.ShoppingCartBeanкласа, който трябва да бъде зареден от зареждащия клас, което се намира в директория:

 > java JWhich com.clarkware.ejb.ShoppingCartBean Class 'com.clarkware.ejb.ShoppingCartBean' намерен в '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class' 

Следващият пример за използване на JWhichпоказва абсолютното име на пътя на първото появяване на javax.servlet.http.HttpServletкласа, който трябва да бъде зареден от зареждащия клас, което се опакова в архивен файл:

 > java JWhich javax.servlet.http.HttpServlet Class 'javax.servlet.http.HttpServlet' намерен в 'file: /home/mclark/lib/servlet.jar! /javax/servlet/http/HttpServlet.class' 

Как работи JWhich

За да определите недвусмислено кой клас ще бъде зареден първи в пътя на класа, трябва да влезете в съзнанието на зареждащия клас. Това не е толкова трудно, колкото звучи - просто го попитайте! Съответният изходен код за JWhichследва. За пълния изходен код вижте Ресурси.

1: публичен клас JWhich {2: 3: / ** 4: * Отпечатва абсолютното име на файла на класа 5: *, съдържащо посоченото име на класа, както е предписано 6: * от текущия път на класа. 7: * 8: * @param className Име на класа. 9: * / 10: публична статична празнота, която (String className) {11: 12: if (! ClassName.startsWith ("/")) {13: className = "/" + className; 14:} 15: className = className.replace ('.', '/'); 16: Име на класа = Име на класа + ".class"; 17: 18: java.net.URL classUrl = 19: new JWhich (). GetClass (). GetResource (className); 20: 21: if (classUrl! = Null) {22: System.out.println ("\ nClass '" + className + 23: "' намерен в \ n '" + classUrl.getFile () + "'"); 24:} else {25: System.out.println ("\ nClass '" + className + 26: "' не е намерен в \ n '"+ 27: System.getProperty (" java.class.path ") +" '"); 28:} 29:} 30: 31: публична статична празнота main (String args []) {32: if (args.length > 0) {33: JWhich.which (args [0]); 34:} else {35: System.err.println ("Употреба: java JWhich"); 36:} 37:} 38:}

First, you need to massage the class name a bit to gain class loader acceptance (lines 12-16). Prepending a "/" to the class name instructs the class loader to match the class name verbatim within the classpath, rather than trying to implicitly prepend the package name of the invoking class. Converting each occurrence of "." to "/" formats the class name as a valid URL resource name required by the class loader.

Next, the class loader is interrogated (lines 18-19) for the resource matching the properly formatted class name. Every Class object maintains a reference to the ClassLoader object that loaded it, so the class loader that loaded the JWhich class itself is interrogated here. The Class.getResource() method actually delegates to the class loader that loaded the class, returning a URL for reading the class file resource, or null if a class file resource with the specified class name could not be found in the current classpath.

Finally, the absolute pathname of the class file containing the specified class name is displayed, if it was found in the current classpath (lines 21-24). As a debugging aid, if the class file was not found in the current classpath, you obtain the value of the java.class.path system property to display the current classpath (lines 24-28).

It's easy to imagine how this simple chunk of code could be invoked in a Java servlet using the servlet engine's classpath or an Enterprise JavaBean (EJB) using the EJB server's classpath. If the JWhich class were loaded by the custom class loader in a servlet engine, for example, then the servlet engine's class loader would be used to find classes. If the servlet engine's class loader is unable to locate a class, it will delegate to its parent class loader. In general, when JWhich is loaded by a class loader, it's able to find all classes loaded by its class loader or any parent class loaders.

Conclusion

Ако необходимостта е майката на цялото изобретение, тогава инструмент, който помага за управление на Java classpath, отдавна е закъснял. Свързаните с Java дискусионни групи и пощенски списъци са пълни с въпроси, свързани с пътя на класа. Трябва да намалим бариерата за влизане за нови разработчици, за да можем всички да продължим да работим на по-високи нива на абстракция. JWhichе прост, но същевременно мощен инструмент, който ще ви помогне да овладеете Java classpath във всяка среда.

Майк Кларк е независим консултант на Clarkware Consulting, специализиран в Java-базирана архитектура, дизайн и разработка, използвайки J2EE технологии. Наскоро завърши разработването и внедряването на бизнес-към-бизнес (B2B) XML сървър за обмен и в момента е консултант по проект за изграждане на J2EE продукт за управление на производителността.

Научете повече за тази тема

  • 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

  • За повече Java трикове, абонирайте се за безплатния бюлетин на Java Tutor на ITworld.com

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

  • Говорете в дискусията за начинаещи Java, модерирана от автора на JavaWorld Джеф Фрисен

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

Тази история „Java Tip 105: Овладяване на пътя на класа с JWhich“ първоначално е публикувана от JavaWorld.