2011-01-19 11 views
2

残念なことに、非スレッドセーフなデータモデルを使用する、古くなったJavaの "Swing"アプリケーションを開発しています。マルチスレッドおよびマルチコアPCのクライアント数が増加するにつれ、データへの非同期アクセスによる擬似ランダムエラーの数も増加します。私たちは6000個のJavaファイルのような巨大なコードベースを持っています。その大部分はかなり大きくて複雑です。実行時にオブジェクトへのすべての読み書きアクセスをインターセプトする方法はありますか?

グローバル静的ReentrantReadWriteLockを作成して、モデルへのアクセスを制御したいと考えています。私の計画は、テストシステムでReentrantReadWriteLockを使用している間は、常に成功して何もしないで、生産システムで使用するダミーのReadWriteLock実装を作成して、移行を段階的に行うことです。

私が必要とするのは、テストシステムでモデルへのすべてのアクセスを「インターセプト」し、アクセスが適切なロック/アンロックブロックのスクープ内にない場合にエラーを記録する方法です。 ReentrantReadWriteLockは、書き込みロックを所有しているかどうかを判断できます。私は、自分がThreadLocalなどを使って読み取りロック状態を追跡できると仮定しています。

Javaでは、どのようにすれば、明確に定義されたクラスセット内の任意のパブリックメソッドへのアクセスを実行時に傍受するコードを記述し、アクセスがロック/グローバルロックを照会することによってブロックをアンロックしますか? AspectJでこれを行うことはできますか?それとも何か?そしてどうやって?

答えて

1

java proxiesが便利です。
既存のオブジェクトにinvokationハンドラを追加することはできませんが、クラスのインスタンスをプロキシで 'ラップする'ことができます。作成されたプロキシオブジェクトはまだMyClassタイプです。

+0

+1。この場合、いくつかのファクトリまたはいくつかの注入メカニズムを使用して、「明確に定義されたクラスのセット」からすべての型のオブジェクトをインスタンス化する必要があることに注意してください。 – Kel

1

私はそれがAspectJでできると仮定していますが、私はそれを知るために十分に使用していません。

代わりに、トラップしてbootclasspathに追加するクラスの修正コピーを使用します。例えばFileInputStreamとFileOutputStreamのコピーを変更します。

テストシステムでは、これは非常にうまく簡単に動作します。私はあなたが生産でこれを行うsugegstしないだろう。

1

これはあなたの状況にどのように当てはまるのかわかりませんが、メソッド呼び出しを傍受する最良の方法は動的プロキシを使用することです。このためには、あなたのクラス用のインターフェイスを作成しなければなりません。ここで

はどのように動的プロキシの仕事の例です:

interface Foo { 
    void setBar(String bar); 
    String getBar(); 
} 

class FooImpl implements Foo { 
    private String bar; 
    // getter and setter 
} 

これはあなたの通常のコードです。今あなたができるのはnew FooImpl()の代りにプロキシを使うことができます。プロキシの場合は、まず[InvocationHandler][1]]が必要です。

class LockHandler implements InvocationHandler { 

    private FooImpl originalOb; 

    public LockHandler(FooImpl originalOb) { 
     this.originalOb = originalOb; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object [] args) { 
     try { 
     if(method.getName().startsWith("set") { 
      // do locking stuff 
     } 
     return method.invoke(originalOb, args); //invoke underlying method 
     } finally { 
     if(method.getName().startsWith("set") { 
      // do post-call locking stuff 
     } 
     }  
    } 
} 

そして、あなたは最終的にあなたのProxyオブジェクトの作成:

Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), 
             new Class[] { Foo.class }, 
             new LockHandler(new FooImpl())); 

今すぐあなたのfooオブジェクトに対するすべての呼び出しは、あなたの呼び出しハンドラに運ばれますが。もちろん、すべてのオブジェクトに対して新しい呼び出しハンドラインスタンスを作成する必要はありません。originalObは、実際にはObjectタイプとして宣言する必要があります。

AspectJのようなアスペクト実装を使用することもできます。AspectJは、使用するのが簡単ですが、導入までに時間がかかりすぎる可能性があります。

関連する問題