为什么 System.setProperty() 不能在运行时更改类路径?

2022-09-03 04:14:58

我指的是以编程方式更改类路径的问题

我阅读并发现System class下有一些函数作为getproperties,我们可以检索属性,然后也可以使用setProperties()设置它。

然而,我得到的答案是它不会起作用。我自己没有尝试过,但是,我正在接电话。

只是为了澄清,如果这些 setProperty() 和 getProperty() 方法无法在运行时更改它,为什么它们会存在。或者这是否仅特定于类路径属性?

如果有人能提出一个他们真正有帮助的场景,我将不胜感激?


答案 1

您当然可以在任何时间点设置所需的任何系统属性。问题是,它会有什么影响吗?对于类路径,答案是否定的。系统类装入器在启动序列的早期阶段初始化。它将类路径复制到自己的数据结构中,并且不会再次读取类路径属性。更改它不会影响系统中的任何内容。

其原因可能有两个。较少的原因是性能。您可能需要构建某种数据结构来快速查找资源,并且每次都重新解析类路径可能效率低下。更重要的原因是安全性。您不希望恶意类更改您下方的类路径并加载另一个类的受损版本。


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

推荐