Почему System.setProperty () не может изменить путь к классам во время выполнения?

Я имею в виду вопрос при программном изменении пути к классам.

Я прочитал и обнаружил, что в классе Система есть функция getproperties, где мы можем получить свойства, а затем также установить их с помощью setProperties ().

Однако я получил ответы, что это не сработает. Я сам не пробовал, но звоню.

Просто чтобы прояснить, зачем нужны эти методы setProperty () и getProperty (), если они не могут изменить их во время выполнения. Или это относится только к свойству classpath?

Буду признателен, если кто-нибудь сможет представить сценарий, в котором они действительно будут полезны?

добавлена ​​информация о свойстве classpath

VonC 07.11.2008 16:11

Примечание. Beanshell (а также Ant и Groovy) может динамически загружать .jars, но проблема в том, что для некоторых вещей попытка загрузить их в пользовательский загрузчик классов beanshell не приветствуется. так что это не всегда работает, но работает большую часть времени.

djangofan 30.10.2011 04:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
16
2
26 279
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

System.setProperty можно использовать для установки некоторой защиты или обработчика протокола в начале программы. Нравиться:

/*
Add the URL handler to the handler property. This informs 
IBMJSSE what URL handler to use to handle the safkeyring 
support. In this case IBMJCE.
*/
System.setProperty("java.protocol.handler.pkgs", "com.ibm.crypto.provider");

или для используя SSL:

System.setProperty("javax.net.ssl.keyStore", context.getRealPath(KEYSTORE));
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.trustStore", context.getRealPath(TRUSTSTORE));
System.setProperty("javax.net.debug", "ssl");
HttpClient httpClient = new HttpClient();
GetMethod httpGet = new GetMethod("https://something.com");
httpClient.executeMethod(httpGet);
return new String(httpGet.getResponseBody());

Но будьте осторожны, потому что это изменяет среду во время выполнения для приложений ВСЕ, работающих в том же jvm.
Если, например, одно приложение должно работать с saxon, а другое с xalan, и оба используют System.setProperty для установки transformerFactory, тогда вы столкнетесь с проблемами

Как сказано в статье Контролируемый System.setProperty,
System.setProperty () может быть злым вызовом.

  • Он на 100% враждебен к нитям
  • Он содержит суперглобальные переменные
  • Когда эти переменные загадочным образом меняются во время выполнения, очень сложно отлаживать.

Что касается свойства classpath, например Я сказал в предыдущем вопросе, его нелегко изменить во время выполнения.

В частности, системное свойство java java.class.path используется для создания связанной ссылки при создании экземпляра JRE, затем не перечитывается. Следовательно, изменения, которые вы вносите в свойство, на самом деле ничего не делают с существующей виртуальной машиной.

Спасибо VonC, действительно информативно. Однако почему поведение свойства пути к классу отличается. Когда вы говорите в начале программы, я предполагаю, что программа была выполнена, и это первое, что она делает. Правильный ?

Nrj 07.11.2008 12:41

Да, системное свойство java.class.path - это скорее информационная любезность для разработчика. Как и все свойства, вам разрешено изменять его с помощью setProperty (), но это не более чем изменение String на карте.

jodonnell 07.11.2008 16:31

Я думаю, что java.security.properties - это еще одно системное свойство, которое читается при запуске JVM и на которое больше не ссылаются. Я полагаю, что возможность изменить любое свойство во время выполнения вызовет больше проблем, чем решит.

bhavanki 07.11.2008 17:41

Есть ли разница между «супер» -глобальными переменными и просто обычными глобальными переменными? :-)

JesperE 29.07.2009 21:16

@JesperE: Да, это происходит из области, в которой известна глобальная переменная. суперглобальная переменная известна во всей программе без необходимости импорта или префикса (например, $_GET в PHP). Здесь суперпеременная известна из всех приложений, работающих в JVM, а не только из одного приложения, как обычная глобальная переменная.

VonC 29.07.2009 22:06

Основная идея getProperty() заключается в том, что программы / код можно настраивать вне JVM, передавая свойства в командной строке с использованием синтаксиса java -Dfoo=bar.

Поскольку вы можете настроить определенное поведение в других программных компонентах (например, в компоненте ведения журнала) в ситуациях, когда у вас нет контроля над командной строкой - подумайте о развертывании в контейнере сервлетов - setProperty() представляет собой удобный способ программного измените настройки, например, перед запуском вашей утилиты ведения журнала.

Проблема classpath заключается в том, что программы обычно читают такие системные свойства только один раз при их первой инициализации. Таким образом, изменение пути к классам после запуска JVM ничего не меняет для самого приложения, потому что JVM уже инициализирована, а изменение некоторой конфигурации ведения журнала после того, как вы уже получили экземпляр Logger (или что-то еще), обычно не будет иметь никакого эффекта. .

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

Вы, безусловно, можете установить любые системные свойства в любой момент времени. Вопрос в том, подействует ли это? В случае пути к классам ответ - НЕТ. Загрузчик системного класса инициализируется на очень ранней стадии процесса запуска. Он копирует путь к классам в свои собственные структуры данных, и свойство classpath больше не читается. Его изменение ни на что не влияет в системе.

Причина этого может быть двоякой. Меньшая причина - производительность. Возможно, вам понадобится какая-то структура данных, созданная для быстрого поиска ресурсов, и каждый раз повторный синтаксический анализ пути к классам может быть неэффективным. Более важная причина - безопасность. Вы не хотите, чтобы мошеннический класс изменил путь к классам под вами и загрузил скомпрометированную версию другого класса.

Изменить путь к классам

Даже если вы не можете установить путь к классам с помощью системных свойств (поскольку JVM считывает системные свойства один раз: при запуске), вы все равно можете изменить путь к классам, принудительно вызвав метод addURL загрузчика классов. Обратите внимание, что в приведенном ниже решении не учитывается текущий поток. Следовательно, это может быть не во всех ситуациях.

Пример решения

Исходный код следующего кода на веб-сайте Sun был удален:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;                   

import java.io.File;
import java.io.IOException;

import java.net.URL;
import java.net.URLClassLoader;

/**
 * Allows programs to modify the classpath during runtime.              
 */                                                                     
public class ClassPathUpdater {                                         
  /** Used to find the method signature. */                             
  private static final Class[] PARAMETERS = new Class[]{ URL.class };   

  /** Class containing the private addURL method. */
  private static final Class<?> CLASS_LOADER = URLClassLoader.class;

  /**
   * Adds a new path to the classloader. If the given string points to a file,
   * then that file's parent file (i.e., directory) is used as the
   * directory to add to the classpath. If the given string represents a
   * directory, then the directory is directly added to the classpath.
   *
   * @param s The directory to add to the classpath (or a file, which
   * will relegate to its directory).
   */
  public static void add( String s )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    add( new File( s ) );
  }

  /**
   * Adds a new path to the classloader. If the given file object is
   * a file, then its parent file (i.e., directory) is used as the directory
   * to add to the classpath. If the given string represents a directory,
   * then the directory it represents is added.
   *
   * @param f The directory (or enclosing directory if a file) to add to the
   * classpath.
   */
  public static void add( File f )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    f = f.isDirectory() ? f : f.getParentFile();
    add( f.toURI().toURL() );
  }

  /**
   * Adds a new path to the classloader. The class must point to a directory,
   * not a file.
   *
   * @param url The path to include when searching the classpath.
   */
  public static void add( URL url )
    throws IOException, NoSuchMethodException, IllegalAccessException,
           InvocationTargetException {
    Method method = CLASS_LOADER.getDeclaredMethod( "addURL", PARAMETERS );
    method.setAccessible( true );
    method.invoke( getClassLoader(), new Object[]{ url } );
  }

  private static URLClassLoader getClassLoader() {
    return (URLClassLoader)ClassLoader.getSystemClassLoader();
  }
}

Ссылка больше не работает: http://forums.sun.com/thread.jspa?threadID=300557

Пример использования

В следующем примере /home/user/dev/java/app/build/com/package добавляется в путь к классам во время выполнения:

try {
  ClassPathUpdater.add( "/home/user/dev/java/app/build/com/package/Filename.class" );
}
catch( Exception e ) {
  e.printStackTrace();
}

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

Pacerier 29.08.2014 09:36

@Pacerier: Спасибо. Возможно иметь собственный URLClassLoader. Решение можно было бы сделать более надежным, найдя все подклассы ClassLoader (docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.htm‌ l) и попытавшись вызвать их метод loadClass, используя имя двоичного класса.

Dave Jarvis 29.08.2014 09:56

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

Pacerier 29.08.2014 10:00

Ты прав. Реализация JVM имеет два загрузчика: загрузчик и загрузчик пользовательских классов. ClassLoaders не загружает классы массивов. docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-‌ 5.3 Однако для большинства практических целей JVM поставляются с URLClassLoader, который можно использовать для внедрения новых путей к классам во время выполнения.

Dave Jarvis 29.08.2014 10:10

Существует также способ изменить java.library.path во время выполнения, для этого просто выполните:

System.setProperty( "java.library.path", newPath);
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null); // that's the key.

Если для этого частного статического поля в классе ClassLoader установлено значение null, при следующей попытке загрузки собственной библиотеки ClassLoader будет снова инициализирован с использованием нового значения в java.library.path.

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