¿Por qué no puede System.setProperty () cambiar el classpath en tiempo de ejecución?

StackOverflow https://stackoverflow.com/questions/271506

  •  06-07-2019
  •  | 
  •  

Pregunta

Me refiero a la pregunta en cambiando el classpath programáticamente.

Leí y descubrí que hay alguna función en la clase Sistema como getproperties donde podemos recuperar las propiedades y luego también podemos configurarla usando setProperties ().

Sin embargo, las respuestas que obtuve fue que no funcionará. No lo he intentado yo mismo, sin embargo, estoy tomando la llamada.

Solo para aclarar, entonces por qué estos métodos setProperty () y getProperty () están ahí si no pueden alterarlo en tiempo de ejecución. ¿O es esto específico de la propiedad classpath solamente?

¿Apreciaré si alguien puede presentar un escenario en el que sean realmente útiles?

¿Fue útil?

Solución

Ciertamente puede establecer las propiedades del sistema que desee en cualquier momento. La pregunta es, ¿tendrá algún efecto? En el caso de classpath, la respuesta es NO. El cargador de clases del sistema se inicializa en un punto muy temprano de la secuencia de inicio. Copia el classpath en sus propias estructuras de datos, y la propiedad classpath no se vuelve a leer. Cambiarlo no afecta nada en el sistema.

La razón de esto puede ser doble. La razón menor es el rendimiento. Es posible que necesite tener algún tipo de estructura de datos construida para la búsqueda rápida de recursos, y volver a analizar classpath cada vez puede ser ineficiente. La razón más importante es la seguridad. No desea que una clase deshonesta cambie el classpath debajo de usted y cargue la versión comprometida de otra clase.

Otros consejos

Modificar Classpath

Aunque no puede establecer el classpath utilizando las propiedades del sistema (porque la JVM lee las propiedades del sistema una vez: al inicio), aún puede cambiar el classpath invocando por la fuerza el método addURL del cargador de clases. Tenga en cuenta que la solución a continuación no tiene en cuenta el hilo actual. En consecuencia, podría no ser exacto en todas las situaciones.

Solución de ejemplo

Se ha eliminado la fuente original en el sitio web de Sun para el siguiente código:

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();
  }
}

El enlace ya no funciona: http://forums.sun.com/thread .jspa? threadID = 300557

Ejemplo de uso

El siguiente ejemplo agregará / home / user / dev / java / app / build / com / package al classpath en tiempo de ejecución:

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

System.setProperty se puede usar para configurar algún controlador de seguridad o protocolo al comienzo de un programa. Me gusta:

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

o para utilizando 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());

Pero cuidado, porque cambia el entorno en tiempo de ejecución para TODAS aplicaciones que se ejecutan en el mismo jvm .
Si, por ejemplo, una aplicación necesita ejecutarse con saxon y la otra con xalan y ambas usan System.setProperty para configurar transformerFactory, entonces se encontrará con problemas

Como se dijo en el artículo Monitoreado System.setProperty ,
System.setProperty () puede ser una llamada malvada.

  • Es 100% hostil a los hilos
  • Contiene variables súper globales
  • Es extremadamente difícil de depurar cuando estas variables cambian misteriosamente en tiempo de ejecución

Con respecto a la propiedad classpath, como dije en un artículo anterior pregunta , no se puede cambiar fácilmente como tiempo de ejecución.

En particular, la propiedad del sistema java java.class.path se usa para construir un enlace vinculado cuando se instancia JRE, luego no se vuelve a leer . Por lo tanto, los cambios que realice en la propiedad realmente no le hacen nada a la máquina virtual existente.

También hay una manera de cambiar java.library.path en tiempo de ejecución, para hacer eso, simplemente haga:

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

Cuando este campo estático privado en la clase ClassLoader se establece en nulo, en el próximo intento de cargar la biblioteca nativa, ClassLoader se inicializará nuevamente utilizando el nuevo valor en java.library.path.

La idea básica de getProperty () es que los programas / código se pueden configurar desde fuera de la JVM, pasando propiedades en la línea de comando usando el java -Dfoo = bar sintaxis.

Como es posible que desee configurar cierto comportamiento en otros componentes de software (como un componente de registro) en situaciones en las que no tiene control sobre la línea de comandos, piense en implementarse en un contenedor de Servlet - setProperty () se presenta como una forma práctica de modificar la configuración mediante programación, por ejemplo, antes de crear instancias de su utilidad de registro.

El problema que presenta el problema classpath es que los programas normalmente solo leerán tales propiedades del sistema exactamente una vez, cuando se inicializan por primera vez. Por lo tanto, cambiar el classpath después del inicio de JVM no cambia nada para su aplicación en sí, porque la JVM ya está inicializada, y cambiar alguna configuración de registro después de que ya haya obtenido una instancia de Logger (o lo que sea), por lo general, tampoco tendrá ningún efecto .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top