关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »使用Java扩展机制加载所有JAR包

    使用Java扩展机制加载所有JAR包

    2014-12-03 00:00:00 出处:ITJS
    分享

    Java 扩展机制在Java教程中被描述为一种“通过标准可扩展的方式来让Java平台上所有应用使用自定义API”。正如在理解扩展机制进行类加载中描述的,“扩展框架充分使用了类加载代理机制”。这种机制会在rt.jar引导(boot)类加载之后,标准classpath中的类加载之前,加载扩展类。

    扩展目录的工作机制在类的加载上与classpath有点类似。对Java应用程序来说,所有扩展目录下JAR文件包含的类都可以访问。然而,会有一些关键的不同点。这些区别会在下面的文字中高亮显示。

    特征 Classpath 扩展机制(可选包)
    作用域 典型的应用相关

    -classpath/-cp java.class.path 可执行JAR Manifest的Class-Path

    主机上所有可能的JRE

    CLASSPATH环境变量
    所有运行在特定JRE上的JVM

    java.ext.dirs

    各种主机上的JRE

    Solaris: /usr/jdk/packages/lib/ext Linux: /usr/java/packages/lib/ext Windows: %SystemRoot%SunJavalibext
    如何指定 .jar文件

    明确的通过名字来指定(包括 .jar) 使用通配符来匹配所有的.jar扩展

    .class Files

    指定目录下的.class文件
    所有在指定目录下的JAR文件都会被加载(即使扩展名不是.jar或者没有扩展名)
    类加载顺序 引导和扩展类加载之后 引导类加载之后,classpath上的类加载之前

    一个最重要且值得重视的问题是,扩展机制会找出所有jar格式的文件,即使文件后缀名不是.jar。这意味着,改变classpath中的jar文件后缀名以此逃过通配符的筛选,这种方法在扩展目录中行不通。

    我会用一些简单的例子来展示一些上面提到的区别。接下来的两段代码是一个简单的HelloWorld类和一个main应用程序中的Main类。Main通过调用main方法来使用HelloWorld类。

    HelloWorld.java

    public class HelloWorld
    {
       @Override
       public String toString()
       {
          return "Hello, World!";
       }
    }

    Main.java

    import static java.lang.System.out;
    
    public class Main
    {
       public static void main(final String[] arguments)
       {
          out.println(new HelloWorld());
       }
    }

    为了展示classpath和扩展机制的主要区别,我将会把编译过的HelloWorld.class文件归档到一个jar包里,命名为HelloWorld.jar。并把它放在一个跟编译过的Main.class不同的目录下。

    为了展示传统的classpath的使用,我把HelloWorld.jar放在一个叫做C:hello的目录下并且会用通配符访问JAR来给Main使用。下面的两个截图对此进行了展示。


    以上两个截图说明,尽管我删掉了当前目录下的HelloWorld.class,Java 主应用仍然能加载它。这是因为Java launcher被告知(通过-classpath这个可选参数)去C:hello目录下寻找。使用扩展机制,不需要把类放到当前目录或者指定到 classpath下就可以加载。接下来的截图展示了这一点。

    上面的截图说明,当某个类是在扩展目录下的某个JAR里,Java launcher甚至不需要把HelloWorld.class放到同一个目录下或者在classpath中指定。这常常被用来说明使用扩展机制的优点。因为所有在这个JRE(或者可能是主机上的所有应用)上运行的程序都可以不用在classpath上指定就能看到扩展目录下的类。

    使用传统classpath方式——指导应用去加载JAR中的类,包含.class文件的JAR文件必须以.jar结尾。接下来的截图展示了当把在 classpath引用的目录下的HelloWorld.jar重命名为HelloWorld.backup之后所发生的事情。

    上面这张图展示了当classpath引用的目录下JAR文件没有以.jar结尾时发生的NoClassDefFoundError异常。可能有点令人惊讶,扩展机制不是这样工作的。所有在扩展目录下的JAR文件,不管后缀名是什么甚至没有后缀名都会被加载。接下来的截图展示了这一点。

    这张图展示了,给在扩展目录中的JAR文件重命名为没有后缀的文件并不妨碍类加载器加载JAR文件中的类。换句话说,类加载机制是通过文件类型而不是文件名或后缀来加载所有在扩展目录中的JAR文件的。正如可选包(Optional Package)概览所总结的,“JAR文件本身没有什么特别的地方,其中包含的class文件也没有让JAR成为已安装过的可选包。只有位于jre/lib/ext下,才可能让JAR成为已安装的可选包。”

    在扩展目录中放包含太多类定义的JAR会有一些风险和负面效果。例如,当我们看到classpath中所指定的类方法存在,还报出NoSuchMethodErrors异常,会令人非常恼火。这是我以前写过众多可以导致NoSuchMethodError问题的其中一个。但是忘记扩展目录下JAR文件中的过时(outdated)和废弃的(obsolete)类是另一个潜在的原因。接下来会展示这一点。

    接下来的两段代码展示了Main.java和HelloWorld.java修改后的版本。特别要注意的是,HelloWorld有一个全新的方法,这个 方法会被新版本的Main调用。在这个例子中,我会把新编译的HelloWorld.class文件和Main放在同一个目录下。这样当我运行Main 的时候,就能证明扩展目录下的JAR中过时的类会比当前目录下的新类优先加载。

    修改后的Hello World.java(新方法)

    public class HelloWorld
    {
       @Override
       public String toString()
       {
          return "Hello, World!";
       }
    
       public String directedHello(final String name)
       {
          return "Hello, " + name;
       }
    }

    修改后的Main.java

    import static java.lang.System.out;
    
    public class Main
    {
       public static void main(final String[] arguments)
       {
          final HelloWorld helloWorld = new HelloWorld();
          out.println(helloWorld);
          out.println(helloWorld.directedHello("Dustin"));
       }
    }

    最后一张截图展示了,扩展目录下过时的HelloWorld类优先于同一目录下的新定义的HelloWorld类加载。甚至当我把当前目录写进 classpath中,扩展目录下的旧版本的类仍然优先。接下来的图也同样展示了扩展目录下的JAR文件“隐藏”了更新的JAR以及其中类的新方法。这些扩展目录下的JAR文件甚至都不是以.jar结尾的。

    刚刚展示的这个例子,在扩展目录下JAR导致的众多问题来说不算很复杂。例子中,至少有一个NoSuchMethodError来提醒这个问 题。一个潜在的更加复杂的情况是,旧的类有和新类一样的方法签名但实现的方式已经过时。在这种情况下,可能没有错误、异常或者throwable中任何一种,但是应用的逻辑不会像预期那样工作。旧的方法可能会一直存在代码的底层直到被发现。当缺乏单元测试或其他测试时尤其如此。

    使用扩展目录会让开发人员变得轻松。因为扩展目录下JAR文件中的类,可以被所有运行在与此扩展目录(如果在操作系统上在主机范围内启用扩展目录,那么所有主机上的JRE都可以访问)关联JRE上的应用访问。然而,随意使用扩展目录会有一定的风险。你会非常容易忘记扩展目录下过时的类。这会妨碍类加载器选择明显应当被加载的版本。这种情况下,本来应该让开发者感觉轻松的扩展机制会让他们非常痛苦。

    Elliotte Rusty Harold提对扩展机制有一个警告:“尽管这些看上去很方便,从长远来看也是引入了一个隐患,迟早你会从一个你根本没想过的地方载入一个错误的类版本。这会浪费你不少时间调试”。Java教程同样提出警告(我在这里也着重强调):“尽管这个机制扩展了平台的核心API,但是应该审慎使用。大部分情况,它是用于像JCP这样标准化比较好的接口,同时也适用于整个站点的接口”。

    尽管扩展(可选包)机制与classpath机制很像,并且它们都用于部分的类加载,两者之间的区别也是非常值得注意的。特别的,记住所有的在扩展目录下的JAR文件(即使它们没有以.jar结尾)都会被加载是很重要的。给那些JARs重命名甚至改变他们的文件后缀名都不足以让类加载器忽略它们。另一方面,使用classpath的时候,重命名classpath中指定的JAR文件会使该JAR无法加载,改变后缀名后,即使在classpath中使用通配符也无法加载所有目录中的JAR。

    一些情况下,扩展机制是比较好的选择,但是这种情况相当少。当处理预期以外的NoSuchMethodErrors问题时,记住扩展机制使很重要的。这样就会去检查看看是否问题就出在扩展的目录中。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    技术热点

    最全面的前端开发指南

    Windows7任务栏桌面下角的一些正在运行的图标不见了

    sql server快速删除记录方法

    SQL Server 7移动数据的6种方法

    SQL Server 2008的新压缩特性

    每个Java程序员必须知道的5个JVM命令行标志

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。