JarClassLoader 类
JarClassLoader
类扩展了java\.net\.URLClassLoader
。顾名思义,URLClassLoader
旨在用于加载通过搜索一组 URL 访问的类和资源。 URL 可以引用目录或 JAR 文件。
除了子类URLClassLoader
之外,JarClassLoader
还利用了另外两个与 JAR 相关的新 API 中的功能,即java\.util\.jar
包和java\.net\.JarURLConnection
类。在本节中,我们将详细介绍JarClassLoader
的构造函数和两个方法。
JarClassLoader 构造函数
构造函数将java\.net\.URL
的实例作为参数。传递给此构造函数的 URL 将在JarClassLoader
的其他位置使用,以查找要从中加载类的 JAR 文件。
public JarClassLoader(URL url) {
super(new URL[] { url });
this.url = url;
}
URL
对象传递给超类URLClassLoader
的构造函数,该构造函数采用URL\[\]
数组而不是单个URL
实例作为参数。
getMainClassName 方法
一旦使用 Binding 了 JAR 的应用程序的 URL 构造了JarClassLoader
对象,就需要一种方法来确定 JAR 文件中的哪个类是应用程序的入口点。这就是getMainClassName
方法的工作:
public String getMainClassName() throws IOException {
URL u = new URL("jar", "", url + "!/");
JarURLConnection uc = (JarURLConnection)u.openConnection();
Attributes attr = uc.getMainAttributes();
return attr != null
? attr.getValue(Attributes.Name.MAIN_CLASS)
: null;
}
您可能会从previous lesson回忆起,由 JAR 文件清单的Main\-Class
Headers 指定了 JARBinding 的应用程序的入口点。为了了解getMainClassName
如何访问Main\-Class
Headers 值,让我们详细看一下该方法,并特别注意它使用的新 JAR 处理特性:
JarURLConnection 类和 JAR URL
getMainClassName
方法使用java\.net\.JarURLConnection
类指定的 JAR URL 格式。 JAR 文件的 URL 的语法如下例所示:
jar:http://www.example.com/jarfile.jar!/
终止符!/
表示 URL 指向整个 JAR 文件。分隔符后的所有内容均指代特定的 JAR 文件内容,如本例所示:
jar:http://www.example.com/jarfile.jar!/mypackage/myclass.class
getMainClassName
方法的第一行是:
URL u = new URL("jar", "", url + "!/");
该语句构造一个表示 JAR URL 的新URL
对象,并将!/
分隔符附加到用于创建JarClassLoader
实例的 URL 上。
java.net.JarURLConnection 类
此类表示应用程序和 JAR 文件之间的通信链接。它具有访问 JAR 文件清单的方法。 getMainClassName
的第二行是:
JarURLConnection uc = (JarURLConnection)u.openConnection();
在此语句中,在第一行中创建的URL
实例将打开URLConnection
。然后将URLConnection
实例强制转换为JarURLConnection
,以便它可以利用JarURLConnection
的 JAR 处理功能。
获取清单属性:java.util.jar.Attributes
在JarURLConnection
打开 JAR 文件的情况下,您可以使用JarURLConnection
的getMainAttributes
方法访问 JAR 文件清单中的头信息。此方法返回java\.util\.jar\.Attributes
的实例,该类 MapJAR 文件清单中的 Headers 名称及其关联的字符串 值。 getMainClassName
中的第三行创建一个Attributes
对象:
Attributes attr = uc.getMainAttributes();
要获取清单的Main\-Class
Headers 的值,getMainClassName
的第四行调用Attributes\.getValue
方法:
return attr != null
? attr.getValue(Attributes.Name.MAIN_CLASS)
: null;
该方法的参数Attributes\.Name\.MAIN_CLASS
指定它是您想要的Main\-Class
Headers 的值。 (Attributes\.Name
类还提供了MANIFEST_VERSION
,CLASS_PATH
和SEALED
之类的静态字段,用于指定其他标准清单 Headers.)
invokeClass 方法
我们已经看到JarURLClassLoader
如何识别 JARBinding 的应用程序中的主类。要考虑的最后一个方法JarURLClassLoader\.invokeClass
,可以调用该主类来启动 JARBinding 的应用程序:
public void invokeClass(String name, String[] args)
throws ClassNotFoundException,
NoSuchMethodException,
InvocationTargetException
{
Class c = loadClass(name);
Method m = c.getMethod("main", new Class[] { args.getClass() });
m.setAccessible(true);
int mods = m.getModifiers();
if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
!Modifier.isPublic(mods)) {
throw new NoSuchMethodException("main");
}
try {
m.invoke(null, new Object[] { args });
} catch (IllegalAccessException e) {
// This should not happen, as we have disabled access checks
}
}
invokeClass
方法具有两个参数:应用程序的入口点类的名称和要传递给入口点类的main
方法的字符串 参数数组。首先,加载主类:
Class c = loadClass(name);
loadClass
方法是从java\.lang\.ClassLoader
继承的。
加载主类后,就使用java\.lang\.reflect
包的反射 API 将参数传递给该类并启动它。您可以参考反射 API上的教程以了解反射。