Если речь идет об изменении classpath на лету, могу предложить реализацию расширяемого класс-лоудера.
| Код | import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.jar.JarFile; import java.util.zip.ZipEntry;
/** * Класс реализует <code>ClassLoader</code>, позволяющий динамически расширять * маршрут поиска классов и ресурсов */ public class ExtendableClassLoader extends ClassLoader implements Serializable {
private Hashtable cache;
private ArrayList paths;
private ClassLoader currentLoader = null;
public ExtendableClassLoader() { cache = new Hashtable(); paths = new ArrayList(); }
/** * Устанавливает новый загрузчик классов для текущего потока, используя * данный экземпляр класса расширенного загрузчика. Перед установкой * выполняется проверка не был ли уже установлен такой загрузчик */ public void setCurrentThreadClassLoader() { ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader instanceof ExtendableClassLoader) return; else { currentLoader = loader; Thread.currentThread().setContextClassLoader(this); } } /** * Добавляет строку в CLASSPATH * @param path Добавляемая строка */ public void addClassPath(String path) { paths.add(path); }
/** * Удаляет строку из CLASSPATH * @param path Удаляемая строка */ public void removeClassPath(String path) { int index = paths.indexOf(path); paths.remove(index); }
/** * Преобразует имя пакета в путь к каталогу * @param className преобразуемое имя класса * @return полученное имя файла */ private String classNameToFileName(String className) { return className.replace( '.', System.getProperty("file.separator").charAt(0)) + ".class"; }
/** * Метод ищет класс в созданном CLASSPATH и возвращает массив байтов * @param className the class to load * @return a byte array containing the byte code of the class */ private byte[] getClassFromAddedClassPaths(String className) { try { ByteArrayOutputStream st = new ByteArrayOutputStream(); String fsep = System.getProperty("file.separator"); String fileName = classNameToFileName(className);
// Поиск класса в добавленных путях поиска for (Iterator e = paths.iterator(); e.hasNext();) { String path = (String) e.next(); File pathFile = new File(path); if (pathFile.isDirectory()) { File f = new File(path + fsep + fileName); if (f.exists()) { FileInputStream fis = new FileInputStream(f); log.info("Class "+className+" was found in "+path); int length = fis.available(); return createByteArray(fis); } } else { JarFile jarFile = new JarFile(pathFile); ZipEntry entry = jarFile.getEntry(fileName); if (entry == null) continue; InputStream stream = jarFile.getInputStream(entry); log.info("Class "+className+" was found in "+path); int length = stream.available(); return createByteArray(stream); } } } catch (Exception e) { e.printStackTrace(); } return null; } /** * Создает массив байтов из входного потока * @param in Входной поток * @return Массив байтов * @throws IOException */ private byte[] createByteArray(InputStream in) throws IOException { final int bufferSize = 2048; byte result[] = new byte[bufferSize]; ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = 0; while ((len = in.read(result)) != -1) out.write(result, 0, len); return out.toByteArray(); }
protected URL findResource(String name) { byte result[] = null; URL res = ClassLoader.getSystemResource(name); if (res != null) return res;
try { String fsep = System.getProperty("file.separator");
// Поиск ресура в добавленных маршрутах поиска for (Iterator e = paths.iterator(); e.hasNext();) { String path = (String) e.next(); File pathFile = new File(path); if (pathFile.isDirectory()) { File f = new File(path + fsep + name); if (f.exists()) return f.toURL(); } else { JarFile jarFile = new JarFile(pathFile); ZipEntry entry = jarFile.getEntry(name); if (entry == null) return null; String url = createJarResourceURL(pathFile, name, fsep); return new URL(url); } } } catch (Exception e) { e.printStackTrace(); } return null; } private String createJarResourceURL(File jarFile, String resourceName, String fsep) throws MalformedURLException { String url = "jar:" + jarFile.toURL() + "!" + fsep + resourceName; return url; }
/** * @see java.lang.ClassLoader#findClass(java.lang.String) */ protected synchronized Class findClass(String className) throws ClassNotFoundException { Class result; byte classData[]; log.info("Class to be found: "+className);
// Проверяем кэш классов. Если класса в кэше нет, тогда применяются другие средства result = (Class) cache.get(className); if (result != null) { return result; }
// Проверяется нет ли такого класса в стандартном пути try { // если загрузчик классов текущего потока уже является расширенным, // используем сохраненное значение загрузчика классов if (Thread.currentThread().getContextClassLoader() instanceof ExtendableClassLoader) { if (this.currentLoader == null) throw new ClassNotFoundException(); else result = this.currentLoader.loadClass(className); } else result = Thread.currentThread().getContextClassLoader().loadClass(className); return result; } catch (ClassNotFoundException e) { log.info("Class was not found in the default classloader"); } catch (Exception e) { log.info("Exception happens: "+e.getStackTrace()); }
// Попытка загрузить класс из добавленного пути classData = getClassFromAddedClassPaths(className); if (classData == null) { throw new ClassNotFoundException(); }
// определение класса result = super.defineClass(className, classData, 0, classData.length); if (result == null) throw new ClassFormatError();
resolveClass(result);
// Полученный класс добавляется в кэш классов cache.put(className, result);
return result; }
}
| |