Можно ли добавить каталог в путь к классам во время выполнения?
Чтобы лучше понять, как все работает в Java, я хотел бы знать, могу ли я динамически добавлять каталог во время выполнения класса.
Например, если я запускаю .jar с помощью "java -jar mycp.jar" и выводю свойство java.class.path, я могу получить:
java.class.path: '.:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java'
Теперь я могу изменить этот путь к классу во время выполнения, чтобы добавить другой каталог? (например, перед первым вызовом класса с использованием .jar, расположенного в этом каталоге, я хочу добавить).
3 ответа
Вы можете использовать следующий метод:
URLClassLoader.addURL(URL url)
Но вам нужно сделать это с отражением, так как метод protected
:
public static void addPath(String s) throws Exception {
File f = new File(s);
URL u = f.toURL();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u});
}
Посмотрите Java след на отражение. Особенно в разделе Недостатки отражения
Обновление 2014: это код из принятого ответа Джонатана Спунера из 2011 года, слегка переписанный, чтобы валидаторы Eclipse больше не создавали предупреждений (устаревшие, rawtypes)
//need to do add path to Classpath with reflection since the URLClassLoader.addURL(URL url) method is protected:
public static void addPath(String s) throws Exception {
File f = new File(s);
URI u = f.toURI();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class<URLClassLoader> urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u.toURL()});
}
Да, вы можете использовать URLClassLoader
.. посмотрите пример здесь. Не использует отражение.
-- редактировать --
Копирование примера из ссылки как предложено.
import javax.naming.*;
import java.util.Hashtable;
import java.net.URLClassLoader;
import java.net.URL;
import java.net.MalformedURLException;
public class ChangeLoader {
public static void main(String[] args) throws MalformedURLException {
if (args.length != 1) {
System.err.println("usage: java ChangeLoader codebase_url");
System.exit(-1);
}
String url = args[0];
ClassLoader prevCl = Thread.currentThread().getContextClassLoader();
// Create class loader using given codebase
// Use prevCl as parent to maintain current visibility
ClassLoader urlCl = URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl);
try {
// Save class loader so that we can restore later
Thread.currentThread().setContextClassLoader(urlCl);
// Expect that environment properties are in
// application resource file found at "url"
Context ctx = new InitialContext();
System.out.println(ctx.lookup("tutorial/report.txt"));
// Close context when no longer needed
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
} finally {
// Restore
Thread.currentThread().setContextClassLoader(prevCl);
}
}
}