从内存动态加载JAR

我想动态加载JAR,直接加载内存。
说,我有一个包含JAR的缓冲区,我想加载JAR中的所有类,或者至少列出JAR中存在的所有文件。 (课程,图像等……)。
如果我加载的第一个类依赖于第二个类,我该怎么办? java知道如何处理这个吗? 或者我自己照顾这个?

既然你说“至少列出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实现。

因此,除非您只是将缓冲区写入临时文件,否则可以归结为实现自己的ClassLoader 。 由于JRE仅支持如上所示的流访问,因此您必须线性扫描以查找请求的资源/类或迭代一次并将条目存储到Map

实现ClassLoader一种替代方法是实现自定义URL处理程序以与URLClassLoader一起使用,该任务将任务减少到查找,如上所述:

 final Map 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写入磁盘,然后您可以使用以下内容将其添加到类路径中:( 完整答案在这里)

 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文件:( 请参阅此处的完整答案)

 ZipFile zipFile = new ZipFile("testfile.zip"); Enumeration zipEntries = zipFile.entries(); String fname; while (zipEntries.hasMoreElements()) { fname = ((ZipEntry)zipEntries.nextElement()).getName(); } 

您应该使用自定义ClassLoader并将JAR文件设置为其类路径。

类总是懒惰地加载,你没有显式加载它们。 一旦JAR位于ClassLoader类路径上,您就可以解析资源。

在这里,您可以使用URLClassloader加载jar。 在示例中我看到我的jar有一个名为com.x.Test的类,它有print方法,下面的代码描述了如何加载类和调用方法,它只是一个例子,但更好地使用了Interfaces,工厂方法和reflection可以使这个代码更好,

 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);