16

プログラムによるクラスパスの変更に関する質問を参照しています。

私が読んだところ、Systemクラスの下に getproperties としてプロパティを取得し、setProperties() を使用して設定できる関数があることがわかりました。

しかし、私が得た答えは、それはうまくいかないということでした。私はこれを自分で試したことはありませんが、電話を受けています。

明確にするために、実行時に変更できない場合、これらの setProperty() および getProperty() メソッドが存在する理由を説明します。それとも、これは classpath プロパティのみに固有ですか?

誰かが本当に役立つシナリオを提示していただければ幸いです。

4

5 に答える 5

13

クラスパスの変更

システム プロパティを使用してクラスパスを設定することはできませんが (JVM は起動時にシステム プロパティを 1 回読み取るため)、addURLクラスローダーのメソッドを強制的に呼び出してクラスパスを変更することはできます。以下の解決策では、現在のスレッドが考慮されていないことに注意してください。したがって、すべての状況で正確であるとは限りません。

ソリューション例

次のコードの Sun の Web サイトの元のソースは削除されました。

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();
}
于 2009-07-29T08:04:13.543 に答える
13

いつでも必要なシステム プロパティを設定できます。問題は、効果があるかどうかです。クラスパスの場合、答えは NO です。システム クラス ローダーは、起動シーケンスの非常に早い段階で初期化されます。クラスパスを独自のデータ構造にコピーし、クラスパス プロパティを再度読み取ることはありません。これを変更しても、システムには何の影響もありません。

この理由は 2 つあります。少ない理由はパフォーマンスです。リソースをすばやく検索するために何らかのデータ構造を構築する必要がある場合があり、毎回クラスパスを再解析するのは非効率的です。より重要な理由はセキュリティです。不正なクラスがクラスパスを変更して、別のクラスの侵害されたバージョンをロードすることは望ましくありません。

于 2008-11-07T13:32:16.043 に答える
10

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 で実行されているすべてのアプリケーションの実行時に環境が変更されるため、注意してください。
たとえば、1 つのアプリケーションを saxon で実行し、もう 1 つのアプリケーションを xalan で実行する必要があり、両方が System.setProperty を使用して、transformerFactory を設定する場合、問題が発生します。

Monitored System.setPropertyの記事で述べたように、
System.setProperty() は悪意のある呼び出しになる可能性があります。

  • 100% スレッド敵対的です
  • スーパーグローバル変数が含まれています
  • これらの変数が実行時に不可解に変化すると、デバッグが非常に困難になります。

クラスパスのプロパティについては、前の質問でも言いましたが、ランタイムとして簡単に変更することはできません。

特に、Java システム プロパティ java.class.path は、JRE がインスタンス化されたときにリンクされたリンクを構築するために使用され、その後再読み込みされません。したがって、プロパティに加えた変更は、既存の仮想マシンには実際には何もしません。

于 2008-11-07T08:26:56.970 に答える
3

実行時に 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 に設定されている場合、次にネイティブ ライブラリをロードしようとすると、java.library.path の新しい値を使用して ClassLoader が再度初期化されます。

于 2011-12-22T00:55:46.810 に答える
0

の基本的な考え方は、構文getProperty()を使用してコマンドラインでプロパティを渡し、JVM の外部からプログラム/コードを構成できるということです。java -Dfoo=bar

コマンド ラインを制御できない状況で、他のソフトウェア コンポーネント (ロギング コンポーネントなど) で特定の動作を構成したい場合があるため (サーブレット コンテナーにデプロイされていると考えてください)、setProperty()プログラムで変更する便利な方法として利用できます。たとえば、ロギング ユーティリティをインスタンス化する前に設定します。

この問題によって示されるclasspath問題は、通常、プログラムが最初に初期化されるときに、そのようなシステム プロパティを 1 回だけ読み取ることです。したがって、JVM の起動後にクラスパスを変更しても、アプリ自体には何も変更されません。JVM は既に初期化されており、Logger インスタンス (またはその他のもの) を既に取得した後にログ構成を変更しても、通常は何の効果もありません。 .

于 2008-11-07T13:25:57.663 に答える