2011-10-25 16 views
23

Javaでの動作をよりよく理解するために、実行時にディレクトリをクラスパスに動的に追加できるかどうかを知りたいと思います。例えば実行時にディレクトリをクラスパスに追加できますか?

、私はの.jar使用起動した場合、 "javaの-jar mycp.jar"と出力のjava.class.pathプロパティは、私が取得することがあります。今

java.class.path: '.:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java' 

このクラスパスを実行時に変更して別のディレクトリを追加することはできますか? (たとえば、追加するディレクトリにある.jarを使用して、クラスへの最初の呼び出しを行う前に)。

答えて

38

次の方法で使用することができます。

URLClassLoader.addURL(URL url) 

をしかし方法がprotectedあるので、あなたが反射でこれを行う必要があります:

public static void addPath(String s) throws Exception { 
    File f = new File(s); 
    URL u = f.toURL(); 
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class urlClass = URLClassLoader.class; 
    Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); 
    method.setAccessible(true); 
    method.invoke(urlClassLoader, new Object[]{u}); 
} 

Reflection上でJavaトレイルを参照してください。 。特に、部分反射の欠点

+0

本当に便利です、ありがとう! –

+0

https://docs.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html –

+0

これは動作していませんフォーム..私はClass.forNameを使用してこの後にクラスをロードできません( " com.mysql.jdbc.Driver "); –

9

はい、URLClassLoaderを使用できます。例hereを参照してください。反射を使用しません。

- 編集 -

例をリンクからコピーしてください。

import javax.naming.*; 
import java.util.Hashtable; 
import java.net.URLClassLoader; 
import java.net.URL; 
import java.net.MalformedURLException; 

public class ChangeLoader { 

    public static void main(String[] args) throws MalformedURLException { 
    if (args.length != 1) { 
     System.err.println("usage: java ChangeLoader codebase_url"); 
     System.exit(-1); 
    } 

    String url = args[0]; 
    ClassLoader prevCl = Thread.currentThread().getContextClassLoader(); 

    // Create class loader using given codebase 
    // Use prevCl as parent to maintain current visibility 
    ClassLoader urlCl = URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl); 

     try { 
     // Save class loader so that we can restore later 
      Thread.currentThread().setContextClassLoader(urlCl); 

     // Expect that environment properties are in 
     // application resource file found at "url" 
     Context ctx = new InitialContext(); 

     System.out.println(ctx.lookup("tutorial/report.txt")); 

     // Close context when no longer needed 
     ctx.close(); 
    } catch (NamingException e) { 
     e.printStackTrace(); 
     } finally { 
      // Restore 
      Thread.currentThread().setContextClassLoader(prevCl); 
     } 
    } 
} 
+0

良い例があり、反射の使用を避ける例です。しかし、おそらくあなたはここにそれらをコピーすることができます - リンクが壊れた場合は? –

+0

@AlexeyGrigorev done。 – Kashyap

+3

これはリフレクションを避けることはできますが、それは価格になります:プロセスクラスパスにパスを追加するのではなく、新しいパスを含む新しいクラスローダを作成し、具体的なスレッド内で使用します。糸。つまり、このように追加されたパスは明示的に変更されたクラスローダーを持つスレッドでのみ記録されます。 –

20

アップデート2014:これは少しEclipseのバリデータは、もはや警告(非推奨、rawtypes)を作成していないように書き直さ2011からジョナサン・スプーナーによって受け入れ答えからコード、ある

//need to do add path to Classpath with reflection since the URLClassLoader.addURL(URL url) method is protected: 
public static void addPath(String s) throws Exception { 
    File f = new File(s); 
    URI u = f.toURI(); 
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class<URLClassLoader> urlClass = URLClassLoader.class; 
    Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); 
    method.setAccessible(true); 
    method.invoke(urlClassLoader, new Object[]{u.toURL()}); 
} 
+2

受け入れられた答えを編集するためにスタックオーバーフローが増えていたと思います。これ以上の重複解答は、私たちがこのサイトで好きなものです。 – Zeemee

+2

@Zeemee私はほとんど覚えていない、おそらく私はこれが縁のケースだと思った。私は受け入れられた答えをあまりにも多く避けることにしました。私は作者の意図以上に行きたくはありませんでした。 – knb

関連する問題