getContextClassLoader
指向Shadov处的线程。有正确答案:
oracle community提到的注意事项也很重要:
以下代码将jar文件添加到构建路径,它在Java 8上正常工作。但是,在Java 9上引发异常,该异常与对URLClassLoader的强制转换有关。有什么想法可以解决吗?最佳解决方案将对其进行编辑以使其与Java 8和9一起使用。
private static int AddtoBuildPath(File f) {
try {
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader, u.toURL());
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | MalformedURLException | IllegalAccessException ex) {
return 1;
}
return 0;
}
您已经碰到the system class loader is no longer a URLClassLoader
的事实。如URLClassLoader
的返回类型所指示,这是一个实现细节,尽管依赖于不可忽略的代码量。
通过注释判断,您正在寻找一种在运行时动态加载类的方法。作为ClassLoader::getSystemClassLoader
,在Java 9中无法通过附加到类路径来完成。
您应该考虑为此创建一个新的类加载器。这具有附加的优势,因为新类没有加载到应用程序类加载器中,因此您将能够摆脱它们。如果您使用Java 9进行编译,则应阅读Alan Bateman points out-它们为您提供了一个全新的抽象概念,用于加载全新的模块图。
前一段时间,我偶然发现了这个问题。我使用了很多类似问题的方法
layers
在运行时动态将路径添加到类路径。该问题中的代码在多个方面可能是不好的样式:1)假设private static int AddtoBuildPath(File f)
返回ClassLoader.getSystemClassLoader()
是未记录的实现细节,并且2)使用反射使URLClassLoader
公开可能是另一种形式。
更干净的动态添加类路径的方法
如果需要通过“ addURL
”使用附加的类路径URL进行类加载,则以下一种干净,优雅且兼容(Java 8到10)的解决方案:
1)通过使用公共Class.forName
方法扩展URL类加载器来编写自己的类加载器>
addURL
2)声明一个类加载器的(单个/应用程序范围内的)对象
public class MyClassloader extends URLClassLoader { public MyClassloader(URL[] urls, ClassLoader parent) { super(urls, parent); } public void addURL(URL url) { super.addURL(url); } }
并通过]实例化>
private final MyClassloader classLoader;
注意:系统类加载器是父级。通过
classLoader = new MyClassloader(new URL[0], this.getClass().getClassLoader());
加载的类知道可以通过classLoader
加载的类,但反之则不行。3)在需要时(动态地)添加其他类路径:
创建驱动程序this.getClass().getClassLoader()
4)通过您的单例类加载器实例化对象或您的应用程序>
File file = new File(path); if(file.exists()) { URL url = file.toURI().toURL(); classLoader.addURL(url); }
注意:由于类加载器在加载类之前先尝试委托给父类加载器(父类加载给其父类),因此必须确保要加载的类对父类加载器不可见,以确保它通过给定的类加载器加载。为了更清楚地说明这一点:如果系统类路径上有
cls = Class.forName(name, true, classLoader);
,然后在自定义ClassPathB
中添加ClassPathB
和一些ClassPathA
,则classLoader
下的类将通过系统类加载器加载,而他们不知道ClassPathB
。但是,如果从系统类路径中删除ClassPathA
,则将通过您的自定义ClassPathB
加载此类,然后ClassPathB下的类就会知道ClassPathA下的类。5)您可以考虑通过以下方式将您的类加载器传递给线程:>
classLoader
如果线程使用
setContextClassLoader(classLoader)
。
getContextClassLoader
指向Shadov处的线程。有正确答案:oracle community提到的注意事项也很重要:
注意事项:
java.util.ServiceLoader使用线程的ClassLoader上下文Thread.currentThread()。setContextClassLoader(specialloader);
java.sql.DriverManager确实支持调用类的ClassLoader,而不是线程的ClassLoader。直接使用Class.forName(“ drivername”,true,new URLClassLoader(urlarrayofextrajarsordirs).newInstance();
javax.activation使用线程的ClassLoader上下文(对于javax.mail重要)。
[如果您只是想读取当前的类路径,例如,因为您想启动另一个具有与当前类路径相同的类路径的JVM,则可以执行以下操作:
Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
默认情况下,无法通过反射访问$ AppClassLoader类中的最终字段,需要将额外的标志传递给JVM:
object ClassloaderHelper {
def getURLs(classloader: ClassLoader) = {
// jdk9+ need to use reflection
val clazz = classloader.getClass
val field = clazz.getDeclaredField("ucp")
field.setAccessible(true)
val value = field.get(classloader)
value.asInstanceOf[URLClassPath].getURLs
}
}
val classpath =
(
// jdk8
// ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs ++
// getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs
// jdk9+
ClassloaderHelper.getURLs(ClassLoader.getSystemClassLoader) ++
ClassloaderHelper.getURLs(getClass.getClassLoader)
)
我找到了这个,并为我工作。
String pathSeparator = Syste .getProperty(“ path.separator”);String [] classPathEntries = System.getProperty(“ java.class.path”).split(pathSeparator);
来自网站--add-opens java.base/jdk.internal.loader=ALL-UNNAMED
getContextClassLoader
指向Shadov处的线程。有正确答案:
oracle community提到的注意事项也很重要:
[如果您只是想读取当前的类路径,例如,因为您想启动另一个具有与当前类路径相同的类路径的JVM,则可以执行以下操作:
Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
默认情况下,无法通过反射访问$ AppClassLoader类中的最终字段,需要将额外的标志传递给JVM:
我找到了这个,并为我工作。
String pathSeparator = Syste .getProperty(“ path.separator”);String [] classPathEntries = System.getProperty(“ java.class.path”).split(pathSeparator);
来自网站--add-opens java.base/jdk.internal.loader=ALL-UNNAMED