Как изменить CLASSPATH в Java?

Как вы изменяете CLASSPATH процесса Java из процесса Java?


Прежде чем спросить меня: "Зачем ты хочешь это сделать?" Я объясню это в ближайшее время.

Когда вы выполняете запуск Clojure REPL, обычно требуется больше банок в вашем CLASSPATH для загрузки Clojure исходного файла, и я хотел бы сделать это, не перезагружая Clojure сам (что на самом деле не является вариантом при использовании Slime на Emacs).

Это причина, по которой я не хочу, чтобы этот вопрос был помечен как некий странный редактор с некоторыми странностями и не учитывался большинством разработчиков Java, которые могут иметь ответ.

Ответ 1

Обновление Q4 2017: прокомментировал ниже vda8888, в Java 9, System java.lang.ClassLoader уже не java.net.URLClassLoader.

См. "Руководство по перенастройке Java 9: ​​Семь наиболее распространенных проблем

Стратегия загрузки класса, которую я только что описал, реализована в новом типе, а в Java 9 - загрузчик классов приложений. Это означает, что это уже не URLClassLoader, поэтому случайные последовательности (URLClassLoader) getClass().getClassLoader() или (URLClassLoader) ClassLoader.getSystemClassLoader() больше не будут выполняться.

java.lang.ModuleLayer будет альтернативным подходом, используемым для того, чтобы влиять на путь модуля (а не путь к классам). См. Например: Модули Java 9 - Основы JPMS.


Для Java 8 или ниже:

Некоторые общие комментарии:

вы не можете (в переносном режиме, который гарантированно работает, см. ниже) изменить путь к системе. Вместо этого вам нужно определить новый ClassLoader.

ClassLoaders работают иерархически... поэтому любой класс, который делает статическую ссылку на класс X, должен быть загружен в тот же ClassLoader, что и X, или в дочерний ClassLoader. Вы не можете использовать какой-либо пользовательский класс ClassLoader, чтобы код, загруженный системой ClassLoader, правильно, если бы он этого не делал раньше. Поэтому вам нужно организовать, чтобы ваш основной код приложения выполнялся в пользовательском ClassLoader в дополнение к дополнительному коду, который вы найдете.
(При этом cracked-all упоминает в комментариях этот пример расширение URLClassLoader)

И вы можете не писать собственный ClassLoader, а просто использовать URLClassLoader. Создайте URLClassLoader с URL-адресом, который не указан в родительских загрузчиках классов.

URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);

A более полное решение будет:

ClassLoader currentThreadClassLoader
 = Thread.currentThread().getContextClassLoader();

// Add the conf dir to the classpath
// Chain the current thread classloader
URLClassLoader urlClassLoader
 = new URLClassLoader(new URL[]{new File("mtFile").toURL()},
                      currentThreadClassLoader);

// Replace the thread classloader - assumes
// you have permissions to do so
Thread.currentThread().setContextClassLoader(urlClassLoader);

Если вы предполагаете, что системный загрузчик JVMs является загрузчиком URLClassLoader (что может быть неверным для всех JVM), вы можете также использовать отражение, чтобы на самом деле изменить системный путь к классам... (но это взлом;)):

public void addURL(URL url) throws Exception {
  URLClassLoader classLoader
         = (URLClassLoader) ClassLoader.getSystemClassLoader();
  Class clazz= URLClassLoader.class;

  // Use reflection
  Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class });
  method.setAccessible(true);
  method.invoke(classLoader, new Object[] { url });
}

addURL(new File("conf").toURL());

// This should work now!
Thread.currentThread().getContextClassLoader().getResourceAsStream("context.xml");

Ответ 2

Я не верю, что вы можете - правильная вещь (я считаю) - создать новый загрузчик классов с новым путем. Кроме того, вы можете написать свой собственный загрузчик классов, который позволяет динамически изменять путь к классам (для этого загрузчика).

Ответ 3

Возможно, вы захотите изучить java.net.URLClassLoader. Это позволяет вам программно загружать классы, которые не были изначально в вашем пути к классам, хотя я не уверен, что это именно то, что вам нужно.

Ответ 5

Возможно, как видно из двух приведенных ниже ссылок, метод VonC кажется лучшим, но проверьте некоторые из этих сообщений и google для "Java Dynamic Classpath" или "Java Dynamic Class Loading" и узнайте какую-то информацию оттуда.

Я бы опубликовал более подробно, но VonC в значительной степени выполнил эту работу.

От Динамическая загрузка файлов классов и Jar.

Также проверьте этот сообщение о форуме солнца.

Ответ 6

String s="java  -classpath abcd/ "+pgmname+" "+filename;   
Process pro2 = Runtime.getRuntime().exec(s); 
BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));

является примером изменения пути к классам в java-программе