Как изменить КЛАСС в Java?

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


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

When you have a Clojure REPL running it is common to need more jars in your CLASSPATH to load a Clojure source file, and I'd like to do it without having to restart Clojure itself (which is not really an option when using it on Slime on Emacs).

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
60
0
73 109
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

Ответ принят как подходящий

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

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

The class loading strategy that I just described is implemented in a new type and in Java 9 the application class loader is of that type.
That means it is not a URLClassLoader anymore, so the occasional (URLClassLoader) getClass().getClassLoader() or (URLClassLoader) ClassLoader.getSystemClassLoader() sequences will no longer execute.

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


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

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

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

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

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

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

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

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");

«Более полное» решение не работает для меня при использовании Java 1.6.0_13 (64-разрядная версия) в Linux. С другой стороны, метод addURL работает должным образом.

Dave Jarvis 01.08.2009 14:00

Это работает, чтобы добавить банку. Но есть ли решение удалить банку? Например, мне нужно обновить банку новым выпуском.

dmarrazzo 22.01.2015 18:04

@dmarrazzo 6+ лет спустя, я не знаю. Попробуйте задать отдельный вопрос.

VonC 22.01.2015 18:18

Я встречаю это решение в другом потоке, но с вашим объяснением я четко знаю, как его использовать. 1+

Bui Anh Tuan 23.06.2017 03:51

Второе решение (предположим, что системный загрузчик классов JVM является URLClassLoader) перестает работать в JRE 9. Загрузчик системных классов больше не является загрузчиком классов URL.

vda8888 06.12.2017 05:01

@ vda8888 Спасибо. Я включил ваш комментарий в ответ для большей наглядности. А также некоторые ссылки.

VonC 06.12.2017 10:33

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

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

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

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

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

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

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

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

Путь к классам изменяется только для дочернего java-процесса, а не для среды, в которой работает ваш код. Это несколько творчески, но для большинства бесполезно.

Edward Anderson 29.05.2014 00:41

Это пример запуска нового процесса Java с новым путем к классам. Не пример изменения чего-либо.

user207421 16.01.2016 03:34

Другие вопросы по теме