Подтвердить что ты не робот

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

Я ссылаюсь на question на программное изменение пути к классам.

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Даже если вы не можете установить путь к классу с помощью свойств системы (поскольку 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 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();
}

Ответ 3

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.
Если, например, одно приложение должно запускаться с саксоном, а другое с помощью xalan, и оба используют System.setProperty для установки transformerFactory, тогда вы столкнетесь с проблемой

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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