`
helloman0907
  • 浏览: 29798 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java的类路径

 
阅读更多
和Java类路径(classpath)打交道的过程中,开发者偶尔会遇到麻烦。这是因为,类装载器实际装入的是哪一个类有时并不显而易见,当应用程序的classpath包含大量的类和目录时,情况尤其严重。本文将提供一个工具,它能够显示出被装入类文件的绝对路径名。
 
  一、Classpath基础
 
  Java虚拟机(JVM)借助类装载器装入应用程序使用的类,具体装入哪些类根据当时的需要决定。CLASSPATH环境变量告诉类装载器到哪里去寻找第三方提供的类和用户定义的类。另外,你也可以使用JVM命令行参数-classpath分别为应用程序指定类路径,在-classpath中指定的类路径覆盖CLASSPATH环境变量中指定的值。
 
  类路径中的内容可以是:文件的目录(包含不在包里面的类),包的根目录(包含已打包的类),包含类的档案文件(比如.zip文件或者.jar文件)。在Unix家族的系统上,类路径的各个项目由冒号分隔,在MS Windows系统上,它们由分号分隔。
 
  类装载器以委托层次的形式组织,每一个类装载器有一个父类装载器。当一个类装载器被要求装载某个类时,它在尝试自己寻找类之前会把请求先委托给它的父类装载器。系统类装载器,即由安装在系统上的JDK或JRE提供的默认类装载器,通过CLASSPATH环境变量或者-classpath这个JVM命令行参数装入第三方提供的类或者用户定义的类。系统类装载器委托扩展类装载器装入使用Java Extension机制的类。扩展类装载器委托自举类装载器(bootstrap class loader)装入核心JDK类。
 
  你可以自己开发特殊的类装载器,定制JVM如何动态地装入类。例如,大多数Servlet引擎使用定制的类装载器,动态地装入那些在classpath指定的目录内发生变化的类。
 
  必须特别注意的是(也是令人吃惊的是),类装载器装入类的次序就是类在classpath中出现的次序。类装载器从classpath的第一项开始,依次检查每一个设定的目录和压缩文件,尝试找出待装入的类文件。当类装载器第一次找到具有指定名字的类时,它就把该类装入,classpath中所有余下的项目都被忽略。
 
  看起来很简单,对吧?
 
  二、可能出现的问题
 
  不管他们是否愿意承认,初学者和富有经验的Java开发者都一样,他们都曾经在某些时候(通常是在那些最糟糕的情形下)被冗长、复杂的classpath欺骗。应用程序所依赖的第三方类和用户定义类的数量逐渐增长,classpath也逐渐成了一个堆积所有可能的目录和档案文件名的地方。此时,类装载器首先装载的究竟是哪一个类也就不再显而易见。如果classpath中包含重复的类入口,这个问题尤其突出。前面已经提到,类装载器总是装载第一个它在classpath中找到的具有合适名字的类,从实际效果看,它“隐藏”了其他具有合适名字但在classpath中优先级较低的类。
 
  如果不小心,你很容易掉进这个classpath的陷阱。当你结束了一天漫长的工作,最后为了让应用程序使用最好、最新的类,你把一个目录加入到了classpath,但与此同时,你却忘记了:在classpath的另一个具有更高优先级的目录下,存放着该类的另一个版本!
 
   三、一个简单的classpath工具
 
  优先级问题是扁平路径声明方法与生俱来固有的问题,但它不是只有Java的classpath才有的问题。要解决这个问题,你只需站到富有传奇色彩的软件巨构的肩膀上:Unix操作系统有一个which命令,在命令参数中指定一个名字,which就会显示出当这个名字作为命令执行时执行文件的路径名。实际上,which命令是分析PATH变量,然后找出命令第一次出现的位置。对于Java的类路径管理来说,这应该也是一个好工具。在它的启发之下,我着手设计了一个Java工具JWhich。这个工具要求指定一个Java类的名字,然后根据classpath的指引,找出类装载器即将装载的类所在位置的绝对路径。
 
  下面是一个JWhich的使用实例。它显示出当Java类装载器装载com.clarkware.ejb.ShoppingCartBean类时,该类第一次出现位置的绝对路径名,查找结果显示该类在某个目录下:
 
  > java JWhich com.clarkware.ejb.ShoppingCartBean
 
  Class 'com.clarkware.ejb.ShoppingCartBean' found in
  '/home/mclark/classes/com/clarkware/ejb/ShoppingCartBean.class'
 
  下面是第二个JWhich的使用实例。它显示出当Java类装载器装载javax.servlet.http.HttpServlet类时,该类第一次出现位置的绝对路径名,查找结果显示该类在某个档案文件中:
 
  > java JWhich javax.servlet.http.HttpServlet
 
  Class 'javax.servlet.http.HttpServlet' found in
  'file:/home/mclark/lib/servlet.jar!/javax/servlet/http/HttpServlet.class'
 
  四、JWhich的工作过程
 
  要精确地测定classpath中哪一个类先被装载,你必须深入到类装载器的思考方法。事实上,具体实现的时候并没有听起来这么复杂——你只需直接询问类装载器就可以了!
 
  
public class JWhich {
  
  /**
  * 根据当前的classpath设置,
  * 显示出包含指定类的类文件所在
  * 位置的绝对路径
  *
  * @param className <类的名字>
  */
   public static void which(String className) {
  
   if (!className.startsWith("/")) {
   className = "/" + className;
   }
   className = className.replace('.', '/');
   className = className + ".class";
  
   java.net.URL classUrl =
   new JWhich().getClass().getResource(className);
  
   if (classUrl != null) {
   System.out.println(" Class '" + className +
   "' found in '" + classUrl.getFile() + "'");
   } else {
   System.out.println(" Class '" + className +
   "' not found in '" +
   System.getProperty("java.class.path") + "'");
   }
   }
  
   public static void main(String args[]) {
   if (args.length > 0) {
   JWhich.which(args[0]);
   } else {
   System.err.println("Usage: java JWhich ");
   }
   }
   }
 
 
  首先,你必须稍微调整一下类的名字以便类装载器能够接受(12-16行)。在类的名字前面加上一个“/”表示要求类装载器对classpath中的类名字进行逐字精确匹配,而不是尝试隐含地加上调用类的包名字前缀。把所有“.”转换为“/”的目的是,按照类装载器的要求,把类名字格式化成一个合法的URL资源名。
 
  接下来,程序向类装载器查询资源,这个资源的名字必须和经过适当格式化的类名字匹配(18-19行)。每一个Class对象维护着一个对装载它的ClassLoader对象的引用,所以这里是向装载JWhich类的类装载器查询。Class.getResource()方法实际上委托装入该类的类装载器,返回一个用于读取类文件资源的URL;或者,当指定的类名字不能在当前的classpath中找到时,Class.getResource()方法返回null。
 
  最后,如果当前的classpath中能够找到指定的类,则程序显示包含该类的类文件所在位置的绝对路径名(21-24行)。作为一种调试辅助手段,如果当前classpath中不能找到指定的类,则程序获取java.class.path系统属性并显示当前的classpath(24-28行)。
 
  很容易想象,在使用Servlet引擎classpath的Java Servlet中,或者在使用EJB服务器classpath的EJB组件中,上面这段简单的代码是如何运作。例如,如果JWhich类是由Servlet引擎的定制类装载器装入,那么程序将用Servlet引擎的类装载器去寻找指定的类。如果Servlet引擎的类装载器不能找到类文件,它将委托它的父类装载器。一般地,当JWhich被某个类装载器装入时,它能够找出当前类装载器以及所有其父类装载器所装入的所有类。
 
  【结束语】
 

 

  如果需要是所有发明之母,那么帮助我们管理Java类路径的工具可以说迟到了很长时间。Java新闻组和邮件列表中充塞着许多有关classpath的问题,现在JWhich为我们提供了一个简单却强大的工具,帮助我们在任何环境中彻底玩转Java类路径。
分享到:
评论

相关推荐

    java类路径定位

    使用方法,className参数为类的全名,不需要.class后缀,如 srcAdd.jsp?className=java.net.URL

    ClassGraph-超快速超轻量级并行化的Java类路径扫描程序

    ClassGraph的核心功能是扫描Java类路径,包括JAR文件、目录和模块。它能够遍历所有的类、接口、枚举、注解等,查找指定的类或具有特定属性的类。这在处理大型项目或依赖关系时特别有用,例如在运行时检测依赖项、...

    下载并配置JDBC驱动:下载JDBC驱动,配置Database Toolbox所需的java类路径。-matlab开发

    [状态,消息] = configureJDBCDriver(vendor) 在MATLAB的preferences目录中下载给定供应商的JDBC驱动程序,并配置java类路径。 状态指示操作是成功、错误还是无操作。 message 与返回的状态相关联,这是一个可选参数...

    通过java类的路径实例化类并调用方法

    通过java类的路径实例化类并调用方法:仅仅知道类的路径,就可以实例化对象,利用反射机制调用其方法

    Java中获取类路径classpath的简单方法(推荐)

    以下是一些获取Java类路径的方法: 1. **使用 `System.getProperty()`** 通过调用 `System.getProperty("java.class.path")` 可以获取到系统属性 `java.class.path` 的值,这个属性包含了JVM的默认类路径。示例...

    JAVA获取各种路径总结

    2. **Java类路径获取的通用方法** - **使用 `getResource` 和 `getResourceAsStream` 方法** - 示例: - `getClass().getResourceAsStream(filePath);` (`filePath` 例如为 "/filename",默认从 WEB-INF/classes...

    classgraph,一个Uber快速、超轻量级Java类路径扫描器、模块扫描仪和注释处理器。.zip

    ClassGraph是一款强大的开源Java工具,它作为一个快速、超轻量级的类路径扫描器、模块扫描仪和注释处理器,广泛应用于各种Java开发场景。这个工具由Luke Daley开发,旨在提供灵活、高效且功能丰富的类扫描解决方案。...

    java项目路径(相关信息)的取得

    - 描述:Java类路径。 - 示例代码:`System.getProperty("java.class.path")` - 应用场景:确定加载类的路径。 16. **`java.library.path`** - 描述:加载库时搜索的路径列表。 - 示例代码:`System....

    告诉你什么是类路径.docx

    Java 类路径是Java开发和运行过程...理解并正确管理Java类路径对于避免程序运行时错误和提高开发效率具有重要意义。在开发和部署Java应用程序时,确保类路径包含所有必需的库和类文件,是确保程序成功运行的关键步骤。

    告诉你什么是类路径.pdf

    总之,理解和正确配置Java类路径对于开发和部署Java应用程序至关重要,因为这直接影响到程序的正常运行和依赖管理。确保类路径包含了所有必需的类库和类文件,能有效地防止上述异常,使程序运行无误。

    java文件路径获取

    - **Resource**: 在Java中通常指的是类路径下的文件,如配置文件、图片等非可执行代码的文件。 - **URL**: Uniform Resource Locator 的缩写,即统一资源定位符,是一种标识Internet资源位置的方式。 #### 三、主要...

    java路径解决方案

    类路径是Java虚拟机(JVM)寻找类文件的路径集合,它决定了哪些目录和.jar文件被JVM用于加载类。默认情况下,Java会搜索当前目录("."),但通常我们需要自定义类路径以包含项目中的库和其他依赖。可以通过以下方式...

    JAVA读取同一路径下所有类及其方法

    这个方法使用 `getClasses` 方法来获取当前类路径下的所有类,然后遍历这些类,检查它们是否继承自 `com.post.common.BaseAction`,如果是,则将其添加到结果列表中。 getClasses 方法 `getClasses` 方法的实现...

    java 获取当前路径

    Java 获取当前路径 Java 获取当前路径是 Java 编程中一个常见的需求,下面我们将讨论如何在 Java 中获取当前路径。 方法一:使用 System.getProperty() 函数 使用 System.getProperty() 函数可以获取当前路径,该...

    classgraph:超级快速的并行Java类路径扫描器和模块扫描器

    ClassGraph是适用于Java,Scala,Kotlin和其他JVM语言的超快速并行化类路径扫描器和模块扫描器。 ClassGraph在Oracle Code One 2018上获得了Duke's Choice奖(该奖项是对Java生态系统中最有用和/或最具创新性的...

    Linux配置Java版gdal环境离线包

    - 配置Java类路径(CLASSPATH)以包含GDAL的Java库。在用户的`.bashrc`或`.bash_profile`文件中添加GDAL的Java库路径,如:`export CLASSPATH=$CLASSPATH:/path/to/gdal/java/lib/*.jar` - 更新系统路径(PATH),...

    使用JavaService把Java程序转换成windows服务

    - `-Djava.class.path` 用来指定Java类路径,确保所有必要的库和类都能被找到。 - `-start` 参数后面跟的是启动类的全限定名。 2. **打包Java程序** 在将Java程序转换为服务之前,需要先将其打包成JAR文件。在...

    Java相对路径总结

    例如,`getClass().getResourceAsStream("/path/to/resource.txt")`将从类路径的根目录开始查找资源。 6. **Java的URL类**:除了`File`类,Java的`java.net.URL`类也可以处理路径,尤其在处理网络资源时。它可以...

Global site tag (gtag.js) - Google Analytics