2009-06-01 4 views
1

(Java API呼び出しを介して)サブプロセスJava仮想マシンを生成し、それと通信したいと思います。java newbie質問:より豊かなJavaサブプロセス

私はGoogle上で適切なものを探しているだけではないかもしれませんが、私はRuntime.exec()を指摘し続けています。これは私が望んでいないものです。私は、標準の入出力を接続し、さまざまなシリアル化技法を使用したり、リモートメソッド呼び出しを使用することができますが、これらは扱いにくい/重量があるようです。 API呼び出しがRuntime.exec( "/ usr/bin/java -cp [system.getclasspath] ...")を呼び出すよりも堅牢になるようです。

多くの依存関係を持つクラスを動的に再読み込みすることはやや難解です(いくつかのサイトで.classファイルを読み込み、[ClassLoader] .defineClassに渡すことに言及していますが、これは依存クラスの読み込みを処理しませんファイルも)。通信帯域幅や待ち時間があまり必要ない場合は、新しいJVMインスタンスが正常に動作すると思います。それはそれとのコミュニケーションが面倒なようです。いずれにしても、この質問はあまり重要ではありません。私はおそらく簡単なルートに行き、どのように依存するクラスファイル(例えば、内部クラスのもの)をロードできるかを見ていきます。

答えて

2

ロードするクラスがメインアプリケーションとは別のJARファイルまたはディレクトリツリーにある場合は、URLClassLoaderを使用して別のスレッドで実行すると問題はありません。 AFAIKのすべてのJavaアプリケーションサーバーはこのように動作するため、確かに実証済みの技術です。

+0

残念ながら、新しいJVMインスタンスが必要です。 "動機付け"の段落に(おそらく不明瞭に)述べられているように、私は本質的に同じ完全修飾クラス名(自動生成され、変更するのが難しいかもしれない)のいくつかの異なる.classファイルを持っています。 http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#loadClass%28java.lang.String,%20boolean%29のように、loadClassは最初に既にロードされているものを検索しますクラス(findLoadedClass)を使用しているため、単に新しいクラスでURLローダーを使用することはできません。 – gatoatigrado

+2

これは、新しいVMを開始する理由ではありません。同一のVM内に同じ完全修飾名を持つ2つの異なるバージョンのクラスを持つことは間違いなく可能です。なぜなら、別のClassLoaderをロードしたときに*別のクラスとみなされるからです。 –

+1

クラスは、その名前とクラスローダーの一意の組み合わせです。アプリケーションサーバは、同じクラス名の多くのバージョンを持ち、いくつかは再ロードして他のものに影響を与えることができます。新しいJVMの開始には有効な用途があります。 GCオプションを変更し、別のバージョンのJavaを実行します。 –

2

私は間違いなく、Tomcat servlet containerで使用されるクラスローダのメカニズムを見てみ推薦する - 彼らは正確同じクラスローディングの問題を持っているように見えると非常によく、それを解決しているように見えます。

0

通信ルートに行く場合は、Java RMIと考える必要があります。 (以下のリストに示されている)

0

ClassRunnerは、現在のJVMと同じクラスパスとライブラリパスを使用して、クラスパス内の任意の使用可能なクラスのメイン機能を実行するためにProcessBuilderをを使用しています。現在のJVMの環境と作業ディレクトリもクローンされます。

警告:ClassRunnerjavaは、現在のJVMのPATHにあることを前提としています。あなたはSystem.getProperty("java.home")に基づいjavaまたはjava.exeを見つけるの周りにいくつかのロジックを配置すること:)

ClassRunner.javaのリスト:

import java.io.BufferedReader; 
import java.io.InputStreamReader; 

public class ClassRunner 
{ 
    private final Class<?> classToRun; 

    public ClassRunner(Class<?> classToRun) 
    { 
     this.classToRun = classToRun; 
    } 

    public void run(String... args) throws Exception 
    { 
     String javaCommand = "java"; 
     String libraryPath = "-Djava.library.path=\"" + System.getProperty("java.library.path") + "\""; 
     String classpath = "\"" + System.getProperty("java.class.path") + "\""; 
     ProcessBuilder processBuilder = new ProcessBuilder(javaCommand, 
       libraryPath, 
       "-classpath", classpath, 
       classToRun.getCanonicalName()); 
     processBuilder.redirectErrorStream(); 

     for (String arg : args) processBuilder.command().add(arg); 
     Process process = processBuilder.start(); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 
     String line; 
     while ((line = reader.readLine()) != null) System.out.println(line); 
     reader.close(); 
     process.waitFor(); 
    } 

    public static void main(String[] args) throws Exception 
    { 
     new ClassRunner(Main.class).run("Hello"); 
    } 
} 

Main.javaのリスト:

public class Main 
{ 
    public static void main(String... args) 
    { 
     System.out.println("testing Main"); 
     for (String arg : args) System.out.println(arg); 
    } 
} 
+0

これは有効なアプローチだと思う理由は、スレッドが証明書の検証なしにSSLを実行するHTTPSのような独立したグローバルな状態が必要なときにあなたを保存します。 –

+0

Akkaの型付き俳優とリモートアクターhttp://doc.akkasource.org/typed-actors-javaは、あなたの問題全体をはるかにリッチな解決策にしています。リモートアクターhttp://doc.akkasource.org/remote-actors-scalaを実行するための詳細なJavaサンプルがあることを願っています。 –

+0

[Akka](http://akka.io/)へのリンクは変更されているようですが、ドキュメントも良く見えます。 –