< 返回技术文档列表

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

发布时间:2021-11-07 01:15:25

本篇文章为大家展示了如何使用Java扩展机制加载所有JAR包,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

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%\Sun\Java\lib\ext

如何指定.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使用。下面的两个截图对此进行了展示。

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

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

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

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

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

<img class="wp-image-13931" src="https://cache.yisu.com/upload/information/20210521/332/448270.jpg" alt="" microsoft yahei'; line-height: 25px;" />

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

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

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

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

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

上述内容就是如何使用Java扩展机制加载所有JAR包,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注血鸟云行业资讯频道。


/template/Home/Zkeys/PC/Static