在 classpath 之外的 jar 中动态加载顶级 class
Dynamically load top-level class in a jar outside of classpath
更新 - 我项目中的所有文件现在都声明了同一个包。但是,我正在加载的 jar 必须在 class 路径之外。我试过 child.loadClass(className)
和 Class.forName(className, false, child);
,但他们似乎都找不到。
我正在编写一个程序,它想要以 jar 的形式获取插件或模块,并像嵌入在 class 路径中一样使用它们。
我在这里和其他网站上看到了很多类似的问题,所以对于重复的问题我深表歉意。但是,到目前为止,我看到的每个答案都没有奏效。我做错了什么吗?
我有一个装满罐子的文件夹。我知道每个 jar 都有一个扩展我的模块 class 的顶级 class。但是,我不知道那些 class 叫什么。
首先,我找到目录中的所有文件。那很好用。然后,对于每个文件,我尝试使用以下代码获取其顶级 class 的实例:
(首先它以 zip 格式打开 jar 以获取所有 classes 的名称,然后查看名称以判断它是否是顶级 class,然后,如果所以,应该加载、实例化并 return 它。)
private static Module jarLoader(String jar){
try{
ZipInputStream zip = new ZipInputStream(new FileInputStream(ModulesDir+"/"+jar));
URL[] myJarFile = new URL[]{new URL("jar","","file:"+ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , Main.class.getClassLoader());
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
className = className.substring(0, className.length() - ".class".length());
String[] classNameParts = className.replace('$', ':').split(":");//I don't know why i have to do this, but it won't split on "$"
if(classNameParts.length == 1){
System.out.println("trying to load "+className);
Class classToLoad = Class.forName(className, false, child);
System.out.println("loaded class "+classToLoad.getName());
if(classToLoad.getSuperclass() == Module.class){
Module instance = (Module) classToLoad.newInstance();
return instance;
}
}
}
}
zip.close();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
它达到了 "trying to load ..." 并显示了 class 的名称,正如我所期望的那样,然后抛出一个 java.lang.ClassNotFoundException
.
使用相同的名称加载 class 当我将它放入源目录中的 .java 文件时工作正常,但它不会从 jar 中获取它。
我做错了什么吗?我怀疑 class 名称可能需要某种前缀或后缀,但我不知道是什么。
感谢您的帮助!
throw ClassNotFoundException
是你的加载jar文件没有添加到class路径下,下面的代码没有成功加载你的jar文件。
URL[] myJarFile = new URL[]{new URL("jar","","file:"+ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , Main.class.getClassLoader());
应该是这样的:
URL[] myJarFile = new URL[]{new URL("jar","",jarFilePath)};
URLClassLoader child = new URLClassLoader (myJarFile, this.getClass().getClassLoader());
而javac
编译class时,里面的class会用完整路径表示,并用$分割,如com/hello/world/TT$InnerClass.class
.
完整样本:
private void jarLoader(){
try{
String ModulesDir = "./test/test.jar";
ZipInputStream zip = new ZipInputStream(new FileInputStream(ModulesDir));
URL[] myJarFile = new URL[]{new URL("jar","",ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , this.getClass().getClassLoader());
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
className = className.substring(0, className.length() - ".class".length());
String[] classNameParts = className.replace('$', ':').split(":");//I don't know why i have to do this, but it won't split on "$"
if(classNameParts.length == 1){
System.out.println("trying to load "+className);
Class classToLoad = Class.forName(className, true, child);
System.out.println("loaded class "+classToLoad.getName());
}
}
}
zip.close();
}catch (Exception e){
e.printStackTrace();
}
}
所有建议似乎都不起作用,因为我需要加载的文件不在我的类路径中。
This answer 虽然有效
更新 - 我项目中的所有文件现在都声明了同一个包。但是,我正在加载的 jar 必须在 class 路径之外。我试过 child.loadClass(className)
和 Class.forName(className, false, child);
,但他们似乎都找不到。
我正在编写一个程序,它想要以 jar 的形式获取插件或模块,并像嵌入在 class 路径中一样使用它们。
我在这里和其他网站上看到了很多类似的问题,所以对于重复的问题我深表歉意。但是,到目前为止,我看到的每个答案都没有奏效。我做错了什么吗?
我有一个装满罐子的文件夹。我知道每个 jar 都有一个扩展我的模块 class 的顶级 class。但是,我不知道那些 class 叫什么。
首先,我找到目录中的所有文件。那很好用。然后,对于每个文件,我尝试使用以下代码获取其顶级 class 的实例:
(首先它以 zip 格式打开 jar 以获取所有 classes 的名称,然后查看名称以判断它是否是顶级 class,然后,如果所以,应该加载、实例化并 return 它。)
private static Module jarLoader(String jar){
try{
ZipInputStream zip = new ZipInputStream(new FileInputStream(ModulesDir+"/"+jar));
URL[] myJarFile = new URL[]{new URL("jar","","file:"+ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , Main.class.getClassLoader());
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
className = className.substring(0, className.length() - ".class".length());
String[] classNameParts = className.replace('$', ':').split(":");//I don't know why i have to do this, but it won't split on "$"
if(classNameParts.length == 1){
System.out.println("trying to load "+className);
Class classToLoad = Class.forName(className, false, child);
System.out.println("loaded class "+classToLoad.getName());
if(classToLoad.getSuperclass() == Module.class){
Module instance = (Module) classToLoad.newInstance();
return instance;
}
}
}
}
zip.close();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
它达到了 "trying to load ..." 并显示了 class 的名称,正如我所期望的那样,然后抛出一个 java.lang.ClassNotFoundException
.
使用相同的名称加载 class 当我将它放入源目录中的 .java 文件时工作正常,但它不会从 jar 中获取它。
我做错了什么吗?我怀疑 class 名称可能需要某种前缀或后缀,但我不知道是什么。
感谢您的帮助!
throw ClassNotFoundException
是你的加载jar文件没有添加到class路径下,下面的代码没有成功加载你的jar文件。
URL[] myJarFile = new URL[]{new URL("jar","","file:"+ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , Main.class.getClassLoader());
应该是这样的:
URL[] myJarFile = new URL[]{new URL("jar","",jarFilePath)};
URLClassLoader child = new URLClassLoader (myJarFile, this.getClass().getClassLoader());
而javac
编译class时,里面的class会用完整路径表示,并用$分割,如com/hello/world/TT$InnerClass.class
.
完整样本:
private void jarLoader(){
try{
String ModulesDir = "./test/test.jar";
ZipInputStream zip = new ZipInputStream(new FileInputStream(ModulesDir));
URL[] myJarFile = new URL[]{new URL("jar","",ModulesDir)};
URLClassLoader child = new URLClassLoader (myJarFile , this.getClass().getClassLoader());
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
className = className.substring(0, className.length() - ".class".length());
String[] classNameParts = className.replace('$', ':').split(":");//I don't know why i have to do this, but it won't split on "$"
if(classNameParts.length == 1){
System.out.println("trying to load "+className);
Class classToLoad = Class.forName(className, true, child);
System.out.println("loaded class "+classToLoad.getName());
}
}
}
zip.close();
}catch (Exception e){
e.printStackTrace();
}
}
所有建议似乎都不起作用,因为我需要加载的文件不在我的类路径中。
This answer 虽然有效