我正在尝试从类似于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);
}
}
由于