2017年第四季度更新:正如vda8888在下面评论的那样,在Java 9中,System java.lang.ClassLoader
不再是java.net.URLClassLoader
。
请参阅“Java 9 迁移指南:七个最常见的挑战”"
我刚才描述的类装入策略是用新类型实现的,在 Java 9 中,应用程序类装入器是该类型的。
这意味着它不再是,因此偶尔或序列将不再执行。URLClassLoader
(URLClassLoader) getClass().getClassLoader()
(URLClassLoader) ClassLoader.getSystemClassLoader()
java.lang.ModuleLayer将是一种用于影响模块路径(而不是类路径)的替代方法。例如,请参阅“Java 9 模块 - JPMS 基础知识”。
对于 Java 8 或更低版本:
一些一般性评论:
您不能(以保证工作的可移植方式,见下文)更改系统类路径。相反,您需要定义一个新的类加载器。
类加载器以分层方式工作...因此,任何对类 X 进行静态引用的类都需要在与 X 相同的 ClassLoader 中加载,或者在子类加载器中加载。你不能使用任何自定义的 ClassLoader 来使系统正确加载的代码 ClassLoader 链接,如果它以前不会这样做的话。因此,除了找到的额外代码外,您还需要安排在自定义 ClassLoader 中运行主应用程序代码。
(话虽如此,在评论中提到了扩展URLClassLoader
的示例)
你可以考虑不编写自己的ClassLoader,而只使用URLClassLoader。创建一个 URLClassLoader,其 url 不在父类加载器 url 中。
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 来说可能并非如此),那么您也可以使用反射来实际修改系统类路径...(但这是一个黑客;)):
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");