public abstract aspect UsingAspect<T, U> { protected T obj; pointcut settingField(T o): set (T+ U+.*) && args(o); pointcut using(): call(U+.new(..)); after(T o): settingField(o) { this.obj = o; } after(): using() { endUsing(this.obj); } protected abstract void endUsing(T o); }この Generic な抽象アスペクトを、それぞれのリソース型について以下のように具体的する。
- 前回の Disposable オブジェクトの例。
public interface UsingDisposable { public static aspect DisposableAspect extends UsingAspect<Disposable, UsingDisposable> { @Override public void endUsing(Disposable o) { if (null != o)((Disposable)o).dispose(); } } }
- java.io の Writer に適用する例
interface UsingWriter { public static aspect UsingWriterAspect extends UsingAspect<Writer, UsingWriter> { @Override protected void endUsing(Writer o) { try { if (null != o) o.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } }
pointcut using(): call(Using<T>+.new(..));
みたいなパラメタライズした書き方ができれば、更に堅牢で経済的なコードになるけど、残念ながら文法的に許されないらしい。)
クライアントコードは以下のようになる
public class Client { public static void main(final String[] args) throws Exception { new UsingWriter(){ PrintWriter s = new PrintWriter("test.txt"); { s.println("one line written"); s.flush(); }}; } }デバッガを使うとか、コンソール入力を待つ行を追加するとかして、適当な箇所で止めながら動かすと、無名クラス生成ブロックの中でだけ ファイル test.txt にロックがかかっているのが確かめられる。 あとはマルチスレッドとネストか。 } } 実行すると以下のようなコンソール出力を得る。
A("r1") used with "x" B("r2") used with "y" A("r3") used with "z" A("r3") disposed B("r2") closed A("r1") disposed割と簡単に using のネストができた。一応、だんだんと実用的になってきた気がする。取りあえずテストコードで使い始めて、パフォーマンスなんかを中心にしばらく観察してから、問題が無ければプロダクトコードで使ってみるような流れで良いか。
0 件のコメント:
コメントを投稿