ClassLoader从jar和目录中加载类的区别

时间:2015-11-19 16:12:46

标签: java java-ee classloader

我正在尝试从类似于JavaEE Web应用程序的树结构加载类。所以我有一个目录,其中包含已编译的类(/ classes)和包含库(/ lib)的兄弟目录。在类包结构中,我使用简单的逻辑编译了类com.test.Test.class:

package com.test;

import org.json.JSONException;
import org.json.JSONObject;

import com.test.GameObjectState;

public class Test extends Thread {  
    @Override
    public void run() {
        JSONObject json = new JSONObject();
        try {
            json.put("state", GameObjectState.REMOVED);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        System.out.println(json.toString());
    }
}

这是我的主要内容:

ClassLoader classLoader = ClassLoaderFactory.createClassLoader(repository);
Class<?> testClass = classLoader.loadClass("com.test.Test");
Thread t = (Thread) testClass.newInstance();
t.start();

我的ClassLoader实现遵循委托模型。在上下文init期间最终JSONObject&amp;将扫描并在lib / java-json.jar中找到JSONException(在里面匹配相应的JarEntry二进制名称)。当JarEntry找到时 - 创建InputStream以在缓冲区中加载数据以定义类。

JSONException成功加载,而JSONObject在ClassFormatError上失败。 Magic是我从java-json.jar中手动提取/ classes目录中的JSONObject,并且没有抛出ClassFormatError,创建了JSONObject并成功打印输出。可能应该注意JSONObject具有在库中编译的内部/嵌套类。

这是我的类加载器

public class WebAppClassLoader extends URLClassLoader {
    private static final String CLASS_FILE_SUFFIX = ".class";
    private static final String JAR_FILE_SUFFIX = ".jar";
    private static final String CLASS_NOT_FOUND = "Class %s not found";

    private File classesDirectory;
    private Map<String, Class<?>> classes;

    public WebAppClassLoader(File classesDirectory, URL[] urls) {
        super(urls);
        this.classesDirectory = classesDirectory;
        this.classes = new ConcurrentHashMap<String, Class<?>>();
    }

    public static WebAppClassLoader newInstance(File classesDirectory, File libDirectory) throws IOException {
        File[] jars = libDirectory.listFiles(new JarFilter());
        Set<URL> jarUrls = new HashSet<URL>();
        for(File jar : jars) {
            jarUrls.add(jar.toURI().toURL());
        }
        return new WebAppClassLoader(classesDirectory, jarUrls.toArray(new URL[jarUrls.size()]));
    }

    protected static class DirectoryFilter implements FileFilter {
        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    }

    protected static class ClassFilter implements FileFilter {
        @Override
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(CLASS_FILE_SUFFIX);
        }
    }

    protected static class JarFilter implements FileFilter {
        @Override
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(JAR_FILE_SUFFIX);
        }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> result = null;

        byte[] buffer = null;
        try {
            buffer = scanClasses(classesDirectory, asPathName(name));
            if(buffer == null) {
                buffer = scanLib(asPathName(name).replace('\\', '/'));
            }
            if(buffer != null) {
                result = defineClass(name, buffer, 0, buffer.length);
                classes.put(name, result);
            }
        } catch(IOException e) {
            e.printStackTrace();
        }

        if(result == null) {
            String error = String.format(CLASS_NOT_FOUND, name);
            throw new ClassNotFoundException(error);
        }

        return result;
    }

    private byte[] scanClasses(File file, String path) throws IOException {
        byte[] result = null;
        File[] directories = file.listFiles(new DirectoryFilter());
        File[] classes = file.listFiles(new ClassFilter());

        for(File classFile : classes) {
            if(classFile.getAbsolutePath().endsWith(path)) {
                InputStream input = new FileInputStream(classFile);
                input.read(result = new byte[input.available()]);
                input.close();
                break;
            }
        }

        if(result == null) {
            for(File directory : directories) {
                result = scanClasses(directory, path);
                if(result != null) {
                    break;
                }
            }
        }

        return result;
    }

    private byte[] scanLib(String path) throws IOException {
        byte[] result = null;

        for(URL url : getURLs()) urlLoop:{
            File file = new File(url.getFile());
            JarFile jarFile = new JarFile(file);
            try {
                Enumeration<JarEntry> entries = jarFile.entries();
                while(entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    if(entry.getName().endsWith(path)) {
                        InputStream input = jarFile.getInputStream(entry);
                        input.read(result = new byte[input.available()]);
                        break urlLoop;
                    }
                }
            }finally {
                jarFile.close();
            }
        }

        return result;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> result = null;

        if(classes.containsKey(name)) {
            result = classes.get(name);
        }else{
            result = super.loadClass(name);
        }

        return result;
    }

    private static String asPathName(String binaryName) {
        return binaryName.replace('.', '\\').concat(CLASS_FILE_SUFFIX);
    }
}

由于

0 个答案:

没有答案