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

获得类的实际加载路径

阅读更多

尽管 Java 类路径看上去是个很简单的概念,但它也经常是困惑和麻烦的源泉。本文将向您展示一个简单的工具,它可以清楚地确定类装载器从您的类路径中载入了什么 Java 类。(1,000 字)
开发人员在处理 Java 类路径时经常会遇到一些尴尬:他们不总是很清楚类装载器将要载入什么类,尤其是在应用程序的类路径被大量的路径和文件充斥的情况下更是如此。在本文中,我将介绍一个工具,它可以显示被载入的类文件的绝对路径。
类路径简介
Java 虚拟机(JVM)使用一个类装载器根据应用程序的需要载入所需的类。CLASSPATH 环境变量告诉类装载器去哪里找第三方和用户自定义的类。您也可以利用 -classpath JVM 命令行参数为每个应用程序指定类路径,这个路径将重载 CLASSPATH 环境变量指定的类路径。

类路径的内容可以是各种目录,例如没有包含在包中的类文件所在的目录,某个包的根目录,或者包含类的压缩文件(.zip 或 .jar 文件等)。类路径中的各个路径在 Unix 类型的系统中用冒号分隔,在 MS Windows 系统中用分号分隔。
类装载器按照一种委托树的形式组织,其中每个类装载器都有一个父类装载器。当系统要求某个类装载器查找一个类时,它在查找类之前首先把该请求委 托给它的父类装载器。您系统中的 JDK 或 JRE 提供的默认类装载器是系统类装载器,它利用 CLASSPATH 环境变量或 -classpath JVM 命令行参数载入第三方和用户自定义的类。系统类装载器委托扩展类装载器载入使用 Java 扩展机制的类。扩展类装载器委托自引导类装载器(委托到此为止)载入 JDK 的核心类。
您可以开发特定的类装载器指导 JVM 如何动态地载入类。例如,大多数 Servlet 引擎使用自定义的类装载器,当指定的类路径中的类发生改变后,它可以动态地重新调入这些 servlet 类。
这里,十分重要而且很让人吃惊的一点是,类装载器根据类在类路径中的存放顺序进行载入。从第一个路径开始,类装载器访问每个指定的目录或压缩文件来查找要载入的类。它载入第一个名字匹配的类,而剩下的路径将被忽略。
听起来很简单,是吗?
类路径中的圈套
无论那些 Java 开发人员承认与否,他们中的新手和老手都时常(通常是最糟糕的时候)被麻烦的类路径所愚弄。随着应用程序中的第三方和用户自定义类的增加,类路径变得拥挤 不堪,所以类装载器首先载入哪个类并不总是那么显而易见的,这一点在类路径中包含路径双重拷贝的情况下尤为突出。请记住,类装载器载入第一个名字匹配的 类,并将其他同名而优先级较低的类“有效”地隐藏起来。
这一切看上去都太简单,以至于我们好像不可能落入类路径的这个圈套。那么,就让我们看一看。在经过了一整天繁重的键盘操作后,您想在类路径中添 加一个目录,以便应用程序可以调入某个类的最新版本。然而,您没有注意到这个类的另一个版本已经位于某个优先级较高的目录中。就这样,您中招了!
JWhich:一个简单的类路径工具
扁平型路径声明中的优先级问题并不是 Java 类路径所独有的。要解决这一问题,您只需站在传说中的软件巨人的肩膀上即可。Unix 操作系统的 which 命令接受一个名字做为参数,只要这个名字是一个命令,它就显示与之相关的可执行文件的路径。这个命令首先扫描 PATH 环境变量,确定要查找的命令出现的第一个位置。这听起来也是一个管理 Java 类路径的强有力的工具。受这个思路的启发,我开始编写一个 Java 程序。这个程序可以根据一个 Java 类名显示需要载入的类文件的绝对路径,它和类路径中指定的路径一致。
下面的 JWhich 示例显示了类 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 示例显示了类 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 如何工作
如果要完全确定类路径中的哪个类会被载入,您就必须搞清楚类装载器的“想法”。这并不像听上去那么难--直接问它就可以了!下面是与 JWhich 相关的代码。有关全部代码,请参见资源。

1:   public class JWhich {
2:
3:     /**
4:      * Prints the absolute pathname of the class file
5:      * containing the specified class name, as prescribed
6:      * by the current classpath.
7:      *
8:      * @param className Name of the class.
9:      */
10:     public static void which(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:        new JWhich().getClass().getResource(className);
20:
21:      if (classUrl != null) {
22:        System.out.println("\nClass '" + className +
23:          "' found in \n'" + classUrl.getFile() + "'");
24:      } else {
25:        System.out.println("\nClass '" + className +
26:          "' not found in \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:      } else {
35:        System.err.println("Usage: java JWhich <classname>");
36:      }
37:    }
38:  } 
 
  
首先,您需要稍微调整一下类的名字,以便类装载器可以接受它(第 12-16 行)。在类名前加上“/”而不是载入该类的包的名称,这样可以指示类装载器在类路径中逐字核对这个类名。将每个“.”换成“/”可以将类的名称转变为一个 有效的 URL 地址,类装载器需要使用这种格式的地址。
接下来,系统向类装载器查询与给定格式的类名称相符的资源(第 18-19 行)。每个 Class 对象都有对它进行载入的 ClassLoader 对象的引用,所以系统会查询载入 JWhich 类的类装载器对象。Class.getResource() 方法实际上委托载入该类的类装载器执行操作,它会返回类文件资源的 URL 地址。如果带有指定类名称的类文件资源不在当前类路径中,它将返回 null。
最后,如果带有指定类名称的类文件资源在当前的类路径中,那么系统将显示它的绝对路径(第 21-24 行)。做为调试手段,如果类文件不在当前类路径中,那么您将获得 java.class.path 系统属性的值,即显示当前的类路径(第 24-28 行)。
在使用 servlet 引擎类路径的 Java servlet 或使用 EJB 服务器类路径的 Engerprise JavaBean (EJB)中,我们可以很容易地想象出上面这些简单代码是如何被载入的。例如在 servlet 引擎中,如果一个自定义的类装载器载入 JWhich 类,那么系统将使用 servlet 引擎的类装载器查找类。如果 servlet 引擎的类装载器不能找到某个类,那么它将委托给它的父类装载器。通常来说,当某个类装载器载入 JWhich 时,它的类装载器或某个父类装载器需要载入的类都可以被找到。
结论
如果需求是发明之母,那么帮助管理 Java 类路径的工具就来得太迟了。与 Java 相关的新闻组和邮件列表中充满了有关类路径的问题。我们需要降低新的开发人员进入这个领域所面临的障碍,以便我们都可以继续工作在一个更高的层次上。 JWhich 是一个简单而功能强大的工具,它可以帮助您掌握任何环境下的 Java 类路径。

  关于作者
Mike Clark 是 Clarkware Consulting 公司的独立顾问,专门负责使用 J2EE 技术进行基于 Java 的结构设计和开发。他最近完成了一个 B2B XML exchange 服务器的开发和发布,目前是一个项目的顾问,该项目要构建一个 J2EE 性能管理产品。
分享到:
评论

相关推荐

    普通java类获取绝对路径

    6. **阅读相关文档**:压缩包中的`Java类中获得相对路径和绝对路径.txt`和`Java普通类中如何获取工程真实路径?.txt`文档可能包含了更具体的实现细节,建议仔细阅读以获取更多信息。 理解这些知识点后,开发者就能...

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    系统类加载器,通常被称为应用类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载应用程序的主类以及应用类路径(classpath)指定的所有类。开发者编写的大部分Java代码都由系统类加载器加载。 类加载器...

    java中获取类加载路径和项目根路径的5种方式分析

    在实际开发中,开发者应根据具体需求选择合适的方式获取类加载路径和项目根路径,以确保程序的灵活性和可维护性。同时,应该注意路径相关的潜在问题,比如路径分隔符的处理,以及不同操作系统的差异。

    java类动态获取相对路径

    如果资源文件是在类的同一个包下,我们可以使用`MyClass.class.getPackage().getName().replace(".", "/")`来获取当前类所在的包路径,然后结合`getResource`得到的URL,可以构造出相对路径。 5. 注意事项 - 在...

    Java类加载内幕.pdf

    应用程序类加载器,也称为系统类加载器,负责加载`java.class.path`属性定义的路径中的类,这是开发者编写的应用程序的默认加载路径。 除了这些内置的类加载器,开发者还可以自定义类加载器,满足特定的需求,例如...

    Java类加载器学习总结.pdf

    Java类加载器是Java运行时环境(JRE)的一个重要组成部分,它负责将Java字节码加载到内存中,使其可以被Java虚拟机(JVM)执行。...在实际开发中,合理使用自定义类加载器,可以实现热部署、模块化开发等高级功能。

    java得到类的路径

    在Java编程语言中,获取类的路径是一项基本但重要的技能,尤其在处理类加载、反射或需要了解类文件实际位置的场景下。本文将深入探讨如何通过Java代码获取类的绝对路径,包括理解代码逻辑、解析关键方法以及讨论可能...

    JavaWeb_servlet(11)_ 通过 ServletContex 获得类路径下的文件路径

    1. `getRealPath()`:这个方法返回一个字符串,表示相对于Web应用根目录的类路径资源的实际文件系统路径。例如,如果你有一个配置文件位于`WEB-INF/classes/config.properties`,你可以使用如下的代码来获取其实际...

    动态加载jar包的实现

    在自定义的类加载器中,我们可以编写代码来从特定的jar包中读取字节码,而不是使用默认的文件系统路径。这通常涉及使用`java.util.zip`包中的`JarFile`类来打开jar文件,并使用`JarEntry`来获取特定的类。 加载jar...

    JSP中得到几种得到路径的方法

    该方法结合了`getRealPath()`和`File`类的功能,返回的是不包含具体文件名的目录路径,例如`D:\resin\webapps\TEST`。这在处理文件操作时特别有用,比如遍历目录下的所有文件或创建新文件夹。 ### 总结与应用场景 ...

    JAVA中获取各种路径

    此方法返回类的资源路径,通常用于获取与类相关的资源文件,例如`/D:/TEST/WebRoot/WEB-INF/classes/pack/`,这在加载配置文件、模板等静态资源时非常有用。 #### (2) 获取工作目录路径:`System.getProperty("user...

    易语言取自身全路径

    3. 使用路径:将得到的路径用于打开配置文件、读写日志、加载资源等操作。 4. 命令行参数处理:如果有必要,可以使用命令行缓冲区_处理命令行参数,这通常在程序有特定命令行选项时进行。 以上就是关于易语言取自身...

    C# 获取文件路径

    在实际开发中,获取文件路径是非常重要的,例如在读取配置文件、加载资源文件、记录日志文件等场景中都需要获取文件路径。 控制台应用程序获取文件路径 在控制台应用程序中,可以使用以下方法获取文件路径: 1. `...

    JAVA中如何得到文件路径.pdf

    - 获取特定类的类加载器资源路径。 - 示例代码: ```java System.out.println(Test.class.getClassLoader().getResource("")); ``` 4. **使用`ClassLoader.getSystemResource("")`**: - 获取系统类加载器的...

    java路径获得几种方法.txt

    // 输出当前类加载器的路径 System.out.println(Thread.currentThread().getContextClassLoader().getResource("/").getPath()); // 输出根目录的路径 System.out.println(System.getProperty("user.dir")); // ...

    获得系统所有进程的路径

    为了实现"获得系统所有进程的路径",我们可以利用Windows API中的`CreateToolhelp32Snapshot`函数创建一个进程快照,然后用`Process32First`和`Process32Next`遍历这个快照,获取每个进程的信息。在`PROCESSENTRY32`...

    MyEclipse复制完整路径

    当你下载了一个新的MyEclipse插件,通常需要将其解压缩,然后将解压得到的插件文件(通常是.jar或.zip文件)放到这个目录下,MyEclipse启动时会自动识别并加载这些插件,从而扩展其功能。 关于"快捷键 alt +ctrl +c...

    java文件路径获取

    - **Classpath**: 是Java运行环境的一个重要概念,它指定了Java虚拟机(JVM)加载类和资源文件的路径。 - **Resource**: 在Java中通常指的是类路径下的文件,如配置文件、图片等非可执行代码的文件。 - **URL**: ...

    安卓 腾讯TBS加载本地文件(word.pdf.ppt)

    总之,腾讯TBS为安卓应用提供了强大的本地文件加载能力,但实际开发过程中需要注意权限管理、文件路径、兼容性等问题。通过不断学习和实践,开发者可以更好地利用TBS提升用户体验,尤其是在处理各种办公文档时。

Global site tag (gtag.js) - Google Analytics