6

我正在尝试将 jar 文件直接加载到内存中而不将其放入 HDD。我曾尝试使用 ClassLoader,但出现错误。

这是我的代码:

自定义类加载器

public class CLS_ClassLoader extends ClassLoader {

    private byte[] bArrData;

    public CLS_ClassLoader(ClassLoader parent, byte[] bArrData) {
        super(parent);

        this.bArrData = bArrData;
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return defineClass(name, bArrData, 0,
                bArrData.length);
    }
}

主要的

ClassLoader tParentClsLoader = CLS_ClassLoader.class.getClassLoader();
CLS_ClassLoader tClsLoader = new CLS_ClassLoader(tParentClsLoader, fileToByteArray("D:/App.jar"));
Class<?> tClass = null;

try {
        tClass = tClsLoader.loadClass("pkg_main.CLS_Main");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

输出

Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1347093252 in class file pkg_main/CLS_Main
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at pkg_main.CLS_ClassLoader.loadClass(CLS_ClassLoader.java:20)
    at pkg_main.CSL_Main.main(CSL_Main.java:27)

我的想法是获取一个加密的 jar 文件,在运行时解密并直接加载到内存中。

对不起,错别字,我的英语说得不好。提前致谢!

4

1 回答 1

3

您的主要错误是 defineClass(...) 需要类字节,而您正在用整个 jar 文件提供它。如果类字节不以 0xCAFEBABE(典型的 Java 类文件头)开头,则会引发实际异常。因此,您需要一个额外的步骤来将类从 jar 文件中排序出来。下面的实现演示了这个想法:

 class CCLoader extends ClassLoader {
    private Map<String, byte[]> classes = new HashMap<String, byte[]>();

    public CCLoader(InputStream in) {
        super(CCLoader.class.getClassLoader());
        try {
            JarInputStream jis = new JarInputStream(in);
            JarEntry je = null;
            String entryName = null;
            while ((je = jis.getNextJarEntry()) != null) {
                entryName = je.getName();
                if (je.getName().endsWith(".class")) {
                    byte[] classBytes = readClass(jis);
                    String canonicalName = entryName.replaceAll("/", ".").replaceAll(".class", "");
                    classes.put(canonicalName, classBytes);
                }
            }
            jis.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private byte[] readClass(InputStream stream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while(true){
            int qwe = stream.read();
            if(qwe == -1) break;
            baos.write(qwe);
        }
        return baos.toByteArray();
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        try {
            return this.getParent().loadClass(name);
        } catch (ClassNotFoundException e) {
            return findClass(name);
        }
    }

    public Class findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = classes.get(name);
        return defineClass(name, classBytes, 0, classBytes.length);
    }

}

按照您的示例,您可以这样尝试:

ClassLoader tClsLoader = new CCLoader(new FileInputStream("C:/commons-io-2.0.1.jar"));
Class<?> tClass = tClsLoader.loadClass("org.apache.commons.io.FileExistsException");
于 2013-08-24T19:01:11.983 回答