我想动态加载JAR,直接加载内存 说,我有一个包含JAR的缓冲区,我想加载JAR中的所有类,或者至少列出JAR中存在的所有文件。 (课程,图像等......) 如果我加载的第一个类依赖于第二个类,我该怎么办? java知道如何处理这个吗?或者我自己照顾这个?
答案 0 :(得分:6)
由于您说“至少列出JAR中存在的所有文件”,让我们从相当简单的任务开始。
假设您的JarFile是一个字节数组byte[] buffer
:
try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) {
for(;;) {
JarEntry nextEntry = is.getNextJarEntry();
if(nextEntry==null) break;
System.out.println(nextEntry);
}
}
从这样的表示中加载类不是开箱即用的,因为标准的ClassLoader
实现依赖于JarFile
实现,它依赖于物理文件而不是抽象。 / p>
因此,除非您只是将缓冲区写入临时文件,否则可以归结为实现自己的ClassLoader
。由于JRE仅支持如上所示的流访问,因此您必须线性扫描以查找请求的资源/类或迭代一次并将条目存储到Map
。
实现ClassLoader
的一种替代方法是实现自定义URL
处理程序以与URLClassLoader
一起使用,从而将任务减少到查找,如上所述:
final Map<String,byte[]> map=new HashMap<>();
try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) {
for(;;) {
JarEntry nextEntry = is.getNextJarEntry();
if(nextEntry==null) break;
final int est=(int)nextEntry.getSize();
byte[] data=new byte[est>0? est: 1024];
int real=0;
for(int r=is.read(data); r>0; r=is.read(data, real, data.length-real))
if(data.length==(real+=r)) data=Arrays.copyOf(data, data.length*2);
if(real!=data.length) data=Arrays.copyOf(data, real);
map.put("/"+nextEntry.getName(), data);
}
}
URL u=new URL("x-buffer", null, -1, "/", new URLStreamHandler() {
protected URLConnection openConnection(URL u) throws IOException {
final byte[] data = map.get(u.getFile());
if(data==null) throw new FileNotFoundException(u.getFile());
return new URLConnection(u) {
public void connect() throws IOException {}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data);
}
};
}
});
try(URLClassLoader cl=new URLClassLoader(new URL[]{u})) {
cl.loadClass( « a class from your JarFile buffer »);
}
答案 1 :(得分:1)
您可能必须先将jar写入磁盘,然后使用以下命令将其添加到类路径中:(full answer here)
URLClassLoader child = new URLClassLoader (myJar.toURL(), 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);
如果要枚举不在类路径中的jar的内容,可以将其视为zip文件:(see full answer here)
ZipFile zipFile = new ZipFile("testfile.zip");
Enumeration zipEntries = zipFile.entries();
String fname;
while (zipEntries.hasMoreElements()) {
fname = ((ZipEntry)zipEntries.nextElement()).getName();
}
答案 2 :(得分:0)
您应该使用自定义ClassLoader
并将JAR文件设置为其类路径。
类总是懒惰地加载,你没有显式加载它们。一旦JAR位于ClassLoader
的类路径上,您就可以解析资源。
答案 3 :(得分:0)
在这里,您可以使用URLClassloader加载jar。 在示例中我看到我的jar有一个名为com.x.Test的类,它有print方法,下面的代码描述了如何加载类和调用方法,它只是一个例子,但更好地使用了Interfaces,工厂方法和反射可以使这段代码更好,
File jarFile = new File("myspace\\my.jar");
URLClassLoader loader = new URLClassLoader(new URL[]{jarFile.toURL()});
Class<?> clazz = loader.loadClass("com.x.Test");
clazz.getMethod("print").invoke(clazz.getConstructor().newInstance(), args);