Как вы меняете CLASSPATH в Java? - PullRequest
       50

Как вы меняете CLASSPATH в Java?

59 голосов
/ 31 октября 2008

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


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

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

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

Ответы [ 6 ]

78 голосов
/ 31 октября 2008

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

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

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

java.lang.ModuleLayer будет альтернативным подходом, используемым для воздействия на modulepath (вместо classpath). См., Например, " Модули Java 9 - основы JPMS ".


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

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

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

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

И вы можете не писать свой собственный ClassLoader, а просто использовать вместо него URLClassLoader. Создайте URLClassLoader с URL, которые не в 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);

Если вы предполагаете, что системный загрузчик классов JVM является 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");
3 голосов
/ 31 октября 2008

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

2 голосов
/ 20 июля 2011

Нет необходимости писать собственный загрузчик классов! Есть clojure.lang.DynamicClassLoader .

http://blog.japila.pl/2011/01/dynamically-redefining-classpath-in-clojure-repl/

1 голос
/ 31 октября 2008

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

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

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

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

1 голос
/ 31 октября 2008

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

0 голосов
/ 10 октября 2013
String s="java  -classpath abcd/ "+pgmname+" "+filename;   
Process pro2 = Runtime.getRuntime().exec(s); 
BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));

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

...