从内存动态加载 JAR [英] Loading a JAR dynamically from memory
问题描述
我想动态加载 JAR,直接用于内存.
比如说,我有一个包含 JAR 的缓冲区,我想加载 JAR 中的所有类,或者至少列出 JAR 中存在的所有文件.(类、图像等...).
例如,如果我加载的第一个类依赖于第二个类,我该怎么办?java知道如何处理吗?还是我自己来处理?
I want to load a JAR dynamically, straight for memory.
Say, I have a buffer that contains a JAR, and I want to load all the classes inside the JAR, or at least list all of the files that exist inside the JAR. (classes, images, etc...).
What do I do if the first class that I load depends on the second class, for example?
Does java know how to handle this? Or I have take care of this by myself?
推荐答案
既然你说至少列出 JAR 中存在的所有文件",让我们从这个相当简单的任务开始.
Since you said "at least list all of the files that exist inside the JAR", let’s begin with that rather easy task.
假设,你的 JarFile 在一个字节数组中,byte[] 缓冲区
:
Suppose, you have your JarFile in a byte array, 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
实现而不是抽象.
Loading classes from such a representation doesn’t work out-of-the-box because the standard ClassLoader
implementations rely on the JarFile
implementation which relies on a physical file rather than an abstraction.
因此,除非您只是将缓冲区写入临时文件,否则归结为实现您自己的ClassLoader
.由于 JRE 仅支持如上所示的流访问,因此您必须线性扫描以查找请求的资源/类或迭代一次并将条目存储到 Map
中.
So unless you simply write the buffer into a temporary file, it boils down to implement your own ClassLoader
. Since the JRE supports only stream access as shown above, you will have to scan linearly to find a requested resource/class or iterate once and store the entries into a Map
.
实现 ClassLoader
的一种替代方法是实现一个自定义的 URL
处理程序与 URLClassLoader
一起使用,这将任务减少到查找如上所述:
One alternative to implementing a ClassLoader
is to implement a custom URL
handler to use together with a URLClassLoader
which reduces the task to the lookup as described above:
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 »);
}
这篇关于从内存动态加载 JAR的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!