动态Jar加载让我感到困惑

时间:2010-07-28 06:18:17

标签: java classloader

从概念上讲,我在装载新罐子时该怎么办? URLClassloader是唯一的选择吗?我应该如何形成这些URL以指向包含更多jar的子目录。

如果有人感觉超级慷慨,那么执行以下操作的一些演示代码将非常有用(让我们假设“jars / A.jar”包含我们要实例化的“myClass”):

  1. 从子目录
  2. 加载一些jar
  3. 从中返回特定类
  4. 实例化该类

4 个答案:

答案 0 :(得分:4)

  

从概念上讲,当我加载一个新的Jar时,我在做什么?

从概念上讲,您没有加载新的JAR。相反,您正在定义一个类加载器,它将根据需要从JAR文件加载代码和其他资源。

  

URLClassloader是唯一的选择吗?

从理论上讲,您可以实现自己的ClassLoader子类,但这并不是您要做的事情所必需的。

  

我应该如何形成这些URL以指向包含更多jar的子目录。

我认为这是你问题的核心。 URLClassLoader构造函数将URL[]参数解释如下:

  

“任何以'/'结尾的URL都假定引用一个目录。否则,假定该URL引用一个JAR文件,该文件将根据需要下载并打开。”

在上面引用文本的第一种情况下,假定该目录是包含要加载资源的树的根。

但我收集到你正在尝试设置一个类加载器,它将从给定目录中的所有JAR文件加载。为此,您需要:

  1. 阅读目录并为任何JAR文件构建File个对象的列表。
  2. 创建一个数组以保存相同数量的URL个实例。
  3. 对于每个JAR文件File,使用File.toURL()创建URL并添加到数组中。 (使用File.toURL()表示您将获得可在您的平台上运行的JAR文件的Kosher“file:”URL。)
  4. 使用URLClassLoader数组创建URL

答案 1 :(得分:2)

真正的短版本:当您加载新的JAR时,您将为Java提供一个新的位置来查找类。

对于更长的解释,维基百科有一篇与此相关的文章:http://en.wikipedia.org/wiki/Java_Classloader

另外,可以尝试:http://onjava.com/pub/a/onjava/2005/01/26/classloading.html

URLClassLoader不是您唯一的选择;看看http://download-llnw.oracle.com/javase/tutorial/deployment/jar/apiindex.html

Re:如何形成URL,来自Java文档(http://download-llnw.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html):

此类加载器用于从引用JAR文件和目录的URL的搜索路径加载类和资源。任何以“/”结尾的URL都被假定为引用目录。否则,假定URL引用将根据需要打开的JAR文件。

改编自How should I load Jars dynamically at runtime?

URLClassLoader child = new URLClassLoader (new URL("jars/A.jar"), this.getClass().getClassLoader());
Class classToLoad = Class.forName ("com.myClass", true, child);
Method method = classToLoad.getDeclaredMethod ("myMethod");
Object instance = classToLoad.newInstance ();
Object result = method.invoke (instance);

此外,上面链接的答案列出了URLClassLoader的更多替代方案(他们提到了OSGi,JCL和其他一些,我没有任何经验,或者我在这里说些什么)。

HTH

答案 2 :(得分:0)

如果已知罐子列表,那么可能更好/更简单的解决方案是将一个Class-Path条目添加到父jar的清单中。这样你就可以完全避免使用自定义类加载器。

Class-Path: jars/A.jar

显然,在构建时不知道从属jar的情况下,这将不起作用。

答案 3 :(得分:0)

简单的方法是在启动程序之前确保依赖JAR在类路径中。


如果要从子目录加载,则需要确定要提供给URLClassLoader的JAR的路径。你可以使用这样的东西来获得程序的路径:

new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())

这有点像黑客,但我不知道有任何正式的方式来获得Java程序。


如果要动态加载JAR,以便可以像在类路径中指定它一样使用它,请查看此thread。它绝对属于不受支持的黑客行为,但它也简单易行。

我使用的修改版本:

import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * Hack to modify classpath at runtime. Can be used to load JARs as if they were
 * loaded from the start.
 * 
 * Warning: May break if URLClassLoader changes
 * 
 * @author Antony Miguel
 */
public class ClasspathHacker {
    /**
     * Add a file to the classpath.
     * 
     * @param pPath
     *            path to the file
     */
    public static void addFile(String pPath) {
        File f = new File(pPath);
        addFile(f);
    }

    /**
     * Add a file to the classpath.
     * 
     * @param pFile
     *            the file to be added
     */
    public static void addFile(File pFile) {
        try {
            addURL(pFile.toURI().toURL());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Add the content pointed to by a URL to the classpath.
     * 
     * @param pURL
     *            the URL pointing to the content to be added
     */
    public static void addURL(URL pURL) {
        /*
         * Use reflection to call addURL on the system classloader, which we
         * expect to be a URLClassLoader
         */
        Method method;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL",
                    new Class[] { URL.class });
            method.setAccessible(true);
            method.invoke(ClassLoader.getSystemClassLoader(),
                    new Object[] { pURL });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}