从概念上讲,我在装载新罐子时该怎么办? URLClassloader是唯一的选择吗?我应该如何形成这些URL以指向包含更多jar的子目录。
如果有人感觉超级慷慨,那么执行以下操作的一些演示代码将非常有用(让我们假设“jars / A.jar”包含我们要实例化的“myClass”):
答案 0 :(得分:4)
从概念上讲,当我加载一个新的Jar时,我在做什么?
从概念上讲,您没有加载新的JAR。相反,您正在定义一个类加载器,它将根据需要从JAR文件加载代码和其他资源。
URLClassloader是唯一的选择吗?
从理论上讲,您可以实现自己的ClassLoader
子类,但这并不是您要做的事情所必需的。
我应该如何形成这些URL以指向包含更多jar的子目录。
我认为这是你问题的核心。 URLClassLoader
构造函数将URL[]
参数解释如下:
“任何以'/'结尾的URL都假定引用一个目录。否则,假定该URL引用一个JAR文件,该文件将根据需要下载并打开。”
在上面引用文本的第一种情况下,假定该目录是包含要加载资源的树的根。
但我收集到你正在尝试设置一个类加载器,它将从给定目录中的所有JAR文件加载。为此,您需要:
File
个对象的列表。URL
个实例。File
,使用File.toURL()
创建URL
并添加到数组中。 (使用File.toURL()
表示您将获得可在您的平台上运行的JAR文件的Kosher“file:”URL。)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();
}
}
}