2009-03-11 9 views
31

プラットフォームとは独立した方法で、Javaアプリケーションを場所とは別の名前で別のプロセスにロードできますか?別のプロセスでJavaアプリケーションを実行する

私はあなたが...

Process process = Runtime.getRuntime().exec(COMMAND); 

経由でプログラムを実行することができます知っている...この方法の主な問題は、このような呼び出しはその後、プラットフォーム固有であるということです。


理想的には、私は

EXECUTE.application(CLASS_TO_BE_EXECUTED); 

...のような単純なものにする方法をラップ...とCLASS_TO_BE_EXECUTEDとしてアプリケーションクラスの完全修飾名を渡すと思います。

+1

私はあなたが正しいと思いますが、main()メソッドでいくつかのクラスを持ち、別々のプロセスでそれらを起動したいのですか? –

+0

exec( "java.exe"、CLASS_TO_BE_EXECUTED.class.getName())を実行するとどうなりますか? –

+0

javaプログラムによって実行されるJavaクラスの実行のためのユーザからの入力の方法br.readLine()のようなものを使用 – paragjain

答えて

34

つのヒント:

System.getProperty("java.home") + "/bin/java"はあなたのJava実行可能ファイルへのパスを提供します。

((URLClassLoader() Thread.currentThread().getContextClassLoader()).getURL()は、現在のアプリケーションのクラスパスを再構築するのに役立ちます。あなたは本当に別のJVMをオフフォークする必要があるよろしいです:TofuBeerが言っていたもので、次の

Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)

+8

3番目のヒント:プラットフォームに依存しないようにするには、urls.join( ":")を使用しないでください。 – jdigital

+2

ファイル。some_constantの代わりに:(あなたはsome_constantを調べることができます:-) – TofuBeer

+2

http://java.sun.com/j2se/1.4.2/docs/api/java/io/File.html#pathSeparatorCha – Jean

3

実際にネイティブで起動する必要がありますか? "main"メソッドを直接呼び出すことができますか?メインについての唯一の特別なことは、VMランチャーがそれを呼び出すことです。

2
public abstract class EXECUTE { 

    private EXECUTE() { /* Procedural Abstract */ } 

    public static Process application(final String CLASS_TO_BE_EXECUTED) { 

     final String EXEC_ARGUMENT 
     = new StringBuilder(). 
       append(java.lang.System.getProperty("java.home")). 
       append(java.io.File.separator). 
       append("bin"). 
       append(java.io.File.separator). 
       append("java"). 
       append(" "). 
       append(new java.io.File(".").getAbsolutePath()). 
       append(java.io.File.separator). 
       append(CLASS_TO_BE_EXECUTED). 
       toString(); 

     try {  

      return Runtime.getRuntime().exec(EXEC_ARGUMENT); 

     } catch (final Exception EXCEPTION) {  

      System.err.println(EXCEPTION.getStackTrace()); 
     } 

     return null; 
    } 
} 
1

は、その後、あなたのEXECUTE.applicationは(擬似コード)だけでしょうか? JVMは、最近並行処理をサポートしているので、新しいスレッドや2つのスレッド(Foo#main(String [])への呼び出しが必要な場合もあれば、不要な場合もあります)。詳細はjava.util.concurrentを参照してください。

フォークする場合は、必要なリソースを見つけるのに必要な複雑さを自分で設定します。つまり、アプリケーションが頻繁に変更され、多数のjarファイルに依存している場合は、それらをすべてクラスパスargに渡すことができるようにする必要があります。さらに、このようなアプローチでは、(現在実行中の)JVMの場所(正確ではない可能性があります)と現在のクラスパスの場所の両方を推測する必要があります(正確になる可能性は低くなります。スレッドが呼び出されました - jar、jnlp、展開された.classes dir、いくつかのコンテナなど)。

一方、静的な#mainメソッドへのリンクには落とし穴があります。静的修飾子は、他のコードに漏れるという厄介な傾向があり、一般的には設計思想的な人々によって悩まされています。

+0

RMIが後で関与し、プロセスがメインの「カーネル」プロセスのデーモンとして機能し、それらが同じコンピュータ上になくてもネットワーク上の他の場所にある可能性があります。私はオリジナルのフレーズがより多くの読者に役立つと思った。 –

54

ので、それは可能なのです。 Javaシステムのプロパティは、Javaコマンドへのパスを提供するのに十分な情報を提供し、クラスパスはプラットフォームに依存しない方法で提供されます。

public final class JavaProcess { 

    private JavaProcess() {}   

    public static int exec(Class klass) throws IOException, 
               InterruptedException { 
     String javaHome = System.getProperty("java.home"); 
     String javaBin = javaHome + 
       File.separator + "bin" + 
       File.separator + "java"; 
     String classpath = System.getProperty("java.class.path"); 
     String className = klass.getCanonicalName(); 

     ProcessBuilder builder = new ProcessBuilder(
       javaBin, "-cp", classpath, className); 

     Process process = builder.start(); 
     process.waitFor(); 
     return process.exitValue(); 
    } 

} 

あなたはそうのように、この方法を実行します:

int status = JavaProcess.exec(MyClass.class); 

が、私はそれはクラスがクラスパスになければならないので、実際のクラスではなく、名前の文字列表現を渡す意味を成していたと思いましたとにかくこれが動作するために。

+3

何らかの種類のサーバを起動したい場合は、プロセスビルダーで( 'start()'の前に) 'redirectOutput(...)'と 'redirectError(...)を使わなければならないかもしれません。あなたはそれに連絡することができないかもしれません。しかし、理由はわかりません... – nyg

+0

外部プロセスが作業を続行できるように、分離モードで新しいプロセスを実行する方法 – daydreamer

+0

ありがとう! "-cp"を実際のクラスパスから分離することは助けになりました。 1つの文字列としてまとめると「Unrecognized option:-cp 」というエラーが出ます。 – asgs

4

これはあなたにとって過度のものかもしれませんが、Project Akumaはあなたが望むものよりも多くを行います。 私はそれを発見しましたthis entryさんは、サンフランシスコのロックスタートプログラマーの1人ですごく便利なブログです。

+1

Githubに移動したようです。 OracleがJenkins/Hudsonの全機能をどのように活用しているかを考えれば理にかなっています。 – StaxMan

1

これをJava GUIから実行すると、バックグラウンドで実行されるという問題が発生します。 コマンドプロンプトがまったく表示されません。

これを回避するには、 "cmd.exe" AND "start"でjava.exeを実行する必要があります。 なぜか分かりませんが、 "cmd/c start"を入力すると、実行時にコマンドプロンプトが表示されます。

しかし、「開始」との問題は、それが CであるとしてJavaのexeファイルへのパスが通常持っているアプリケーション (へのパスにスペースがあればということである:\プログラムファイル\のJava \ jre6には、 \ bin \ java.exeまたはそれに類するもの) 開始は "c:\ Programを見つけることができません"と失敗します

C:\ Program Files \ Java \ jre6 \ bin \ java.exeを引用符で囲む必要があります java.exeに渡すパラメータについて、startが文句を言っています。 "システムはファイル-cpを見つけることができません。"

"Program Files"のスペースをバックスラッシュでエスケープすることも機能しません。 したがって、スペースを使用しないことが考えられます。 bat拡張子を持つ一時ファイルを生成し、コマンドにスペースを入れて と入力し、batを実行します。 しかし、起動時にバットを実行しても、終了時には終了しません。 バッチファイルの最後に "exit"を付ける必要があります。

これはまだおかしなようです。

代わりに、私は "Program Files"のスペースで引用スペース引用符を使用すると、実際にstartで動作することがわかりました。変更上記EXECUTEクラスで

文字列ビルダーはに追加:実際のコードは(テストの形で)ので、次のようになりstepanchegの答え@上の拡大

append("cmd /C start \"Some title\" "). 
append(java.lang.System.getProperty("java.home").replaceAll(" ", "\" \"")). 
append(java.io.File.separator). 
append("bin"). 
append(java.io.File.separator). 
append("java"). 
append(" "). 
append(new java.io.File(".").getAbsolutePath()). 
append(java.io.File.separator). 
append(CLASS_TO_BE_EXECUTED). 
関連する問題