2017 年第四季度更新:正如vda8888在下面评论的那样,在 Java 9 中,系统不再是.java.lang.ClassLoader
java.net.URLClassLoader
请参阅“ Java 9 迁移指南:七个最常见的挑战”
我刚刚描述的类加载策略是在一种新类型中实现的,而在 Java 9 中,应用程序类加载器就是这种类型。
这意味着它URLClassLoader
不再是 a,因此偶尔(URLClassLoader) getClass().getClassLoader()
或(URLClassLoader) ClassLoader.getSystemClassLoader()
序列将不再执行。
java.lang.ModuleLayer将是用于影响模块路径(而不是类路径)的替代方法。例如,参见“ Java 9 模块 - JPMS 基础知识”。
对于 Java 8 或更低版本:
一些一般性评论:
您不能(以保证工作的可移植方式,见下文)更改系统类路径。相反,您需要定义一个新的 ClassLoader。
类加载器以分层方式工作......因此,任何对类 X 进行静态引用的类都需要加载到与 X 相同的类加载器中,或者加载到子类加载器中。您不能使用任何自定义 ClassLoader 来使系统 ClassLoader 链接正确加载代码,如果以前没有这样做的话。因此,除了您找到的额外代码之外,您还需要安排在自定义 ClassLoader 中运行您的主要应用程序代码。
(话虽如此,评论中都提到了这个扩展的 URLClassLoader
例子)
您可能会考虑不编写自己的 ClassLoader,而只需使用 URLClassLoader。使用不在父类加载器 url 中的url 创建一个 URLClassLoader 。
URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);
更完整的解决方案是:
ClassLoader currentThreadClassLoader
= Thread.currentThread().getContextClassLoader();
// Add the conf dir to the classpath
// Chain the current thread classloader
URLClassLoader urlClassLoader
= new URLClassLoader(new URL[]{new File("mtFile").toURL()},
currentThreadClassLoader);
// Replace the thread classloader - assumes
// you have permissions to do so
Thread.currentThread().setContextClassLoader(urlClassLoader);
如果您假设 JVM 系统类加载器是 URLClassLoader(可能并非所有 JVM 都如此),您也可以使用反射来实际修改系统类路径......(但这是一个 hack;)):
public void addURL(URL url) throws Exception {
URLClassLoader classLoader
= (URLClassLoader) ClassLoader.getSystemClassLoader();
Class clazz= URLClassLoader.class;
// Use reflection
Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
method.invoke(classLoader, new Object[] { url });
}
addURL(new File("conf").toURL());
// This should work now!
Thread.currentThread().getContextClassLoader().getResourceAsStream("context.xml");