文档

Java™ 教程
隐藏目录
下载扩展
路径:扩展机制
课程:创建和使用扩展

下载扩展

下载扩展是以JAR文件中的类(和相关资源)组成的。JAR文件的清单可以包含指向一个或多个下载扩展的头部信息。扩展可以通过以下两种方式之一来引用:

请注意,清单中最多只允许存在一个。由Class-Path头部指示的下载扩展仅在下载它们的应用程序(如Web浏览器)的生命周期内被下载。它们的优点是客户端不需要安装任何内容,但缺点是每次需要时都需要重新下载。由Extension-List头部下载的扩展将被安装到下载它们的JRE的/lib/ext目录中。它们的优点是第一次需要时才下载,随后可以在不重新下载的情况下使用。但是,正如本教程后面所示,它们部署起来更加复杂。

由于使用Class-Path头部的下载扩展较为简单,我们先考虑它们。例如,假设a.jarb.jar是同一目录中的两个JAR文件,并且a.jar的清单包含以下头部信息:

Class-Path: b.jar

那么b.jar中的类将作为a.jar中的扩展类。a.jar中的类可以调用b.jar中的类,而无需在类路径上指定b.jar的类。a.jar本身可以是一个扩展,也可以不是。如果b.jar不在与a.jar相同的目录中,则Class-Path头部的值应设置为b.jar的相对路径名。

扮演下载扩展角色的类没有任何特殊之处。之所以被视为扩展,仅仅是因为它们被其他JAR文件的清单所引用。

为了更好地理解下载扩展的工作原理,让我们创建一个扩展并将其应用起来。

示例

假设您想创建一个applet,该applet使用前面一节中的RectangleArea类:

public final class RectangleArea {  
    public static int area(java.awt.Rectangle r) {
        return r.width * r.height;
    }
}

在前一节中,通过将包含RectangleArea类的JAR文件放置在JRE的lib/ext目录中,您将RectangleArea类变为一个已安装的扩展。通过将其变为已安装的扩展,您使任何应用程序都能够像使用Java平台的一部分一样使用RectangleArea类。

如果您希望能够从applet中使用RectangleArea类,情况会有所不同。例如,假设您有一个名为AreaApplet的applet,该applet使用RectangleArea类:

import java.applet.Applet;
import java.awt.*;

public class AreaApplet extends Applet {
    Rectangle r;

    public void init() {    
        int width = 10;
        int height = 5;

        r = new Rectangle(width, height);
    }

    public void paint(Graphics g) {
        g.drawString("矩形的面积为 " 
                      + RectangleArea.area(r), 10, 10);
    }
}

这个applet实例化了一个10 x 5的矩形,然后使用RectangleArea.area方法显示矩形的面积。

然而,你不能假设每个下载和使用你的applet的人都会在他们的系统上有RectangleArea类可用,无论是作为已安装的扩展还是其他方式。解决这个问题的一种方法是从服务器端提供RectangleArea类,你可以通过将其作为下载扩展来实现。

为了看到如何实现这一点,让我们假设你已经将AreaApplet打包在名为AreaApplet.jar的JAR文件中,并且类RectangleArea也被打包在RectangleArea.jar中。为了使RectangleArea.jar被视为下载扩展,RectangleArea.jar必须在AreaApplet.jar的清单文件的Class-Path头部中列出。AreaApplet.jar的清单文件可能如下所示:

Manifest-Version: 1.0
Class-Path: RectangleArea.jar

这个清单文件中Class-Path头部的值为RectangleArea.jar,没有指定路径,表示RectangleArea.jar位于与applet的JAR文件相同的目录中。

关于Class-Path头部的更多信息

如果一个applet或应用程序使用多个扩展,你可以在清单文件中列出多个URL。例如,以下是一个有效的头部:

Class-Path: area.jar servlet.jar images/

Class-Path头部中,任何以“/”结尾的URL都被假定为JAR文件。以“/”结尾的URL表示目录。在前面的示例中,images/可能是一个包含applet或应用程序所需资源的目录。

请注意,一个清单文件中只允许有一个Class-Path头部,并且清单中的每行必须不超过72个字符。如果需要指定的类路径条目超过了一行的长度,可以将它们扩展到后续的续行上。每个续行以两个空格开始。例如:

Class-Path: area.jar servlet.jar monitor.jar datasource.jar
  provider.jar gui.jar

未来的版本可能会移除每个头部只允许一个实例的限制,以及限制每行只能有72个字符的限制。

下载扩展可以进行“级联”,也就是一个下载扩展的清单可以有一个Class-Path头部引用第二个扩展,第二个扩展可以引用第三个扩展,依此类推。

安装下载扩展

在上面的示例中,由applet下载的扩展只在加载applet的浏览器仍在运行时可用。但是,如果在applet和扩展的清单中包含了额外的信息,applet可以触发扩展的安装。

由于此机制扩展了平台的核心API,因此应谨慎使用。它很少适用于仅由单个或一小组应用程序使用的接口。所有可见的符号都应遵循反向域名和类层次结构约定。

基本要求是applet和它使用的扩展在其清单中提供版本信息,并且它们都被签名。版本信息允许Java插件确保扩展代码具有applet所期望的版本。例如,AreaApplet可以在其清单中指定一个areatest扩展:

Manifest-Version: 1.0
Extension-List: areatest
areatest-Extension-Name: area
areatest-Specification-Version: 1.1
areatest-Implementation-Version: 1.1.2
areatest-Implementation-Vendor-Id: com.example
areatest-Implementation-URL: http://www.example.com/test/area.jar

area.jar中的清单将提供相应的信息:

Manifest-Version: 1.0
Extension-Name: area
Specification-Vendor: Example Tech, Inc
Specification-Version: 1.1
Implementation-Vendor-Id: com.example
Implementation-Vendor: Example Tech, Inc
Implementation-Version: 1.1.2

applet和扩展都必须由相同的签名者签名。签署jar文件将在原地修改它们,提供更多信息在它们的清单文件中。签署有助于确保只有可信任的代码被安装。签署jar文件的简单方法是首先创建一个密钥库,然后使用它来保存applet和扩展的证书。例如:

keytool -genkey -dname "cn=Fred" -alias test  -validity 180

将提示您输入密钥库和密钥密码。生成密钥后,可以签署jar文件:

jarsigner AreaApplet.jar test
jarsigner area.jar test

将提示您输入密钥库和密钥密码。有关keytooljarsigner和其他安全工具的更多信息,请参阅Java 2平台安全性工具摘要

这是AreaDemo.html,它加载applet并导致扩展代码被下载和安装:

<html>
<body>
  <applet code="AreaApplet.class" archive="AreaApplet.jar"/>
</body>
</html>

当页面首次加载时,用户会被告知applet需要安装扩展。随后的对话框会通知用户有关已签名的applet。接受两者将在JRE的lib/ext文件夹中安装扩展并运行applet。

在重新启动Web浏览器并加载同一个网页后,只会显示关于小程序签名者的对话框,因为area.jar已经安装。如果在不同的Web浏览器中打开AreaDemo.html(假设两个浏览器都使用相同的JRE),这一点也是正确的。


上一页:已安装的扩展
下一页:了解扩展类加载