Aspectを編みこむ際の型判定
日記で何度か書いていますが.NETのAOPの実装には透過プロキシと実プロキシを使用しています。
実プロキシ(RealProxy)の派生クラスはコンストラクタの引数で指定された型への呼び出しを全て補足することができ、そのメッセージの処理をInvokeメソッドでオーバライドすることができるのでこの振る舞いを利用してAspectを型への呼び出しの前後に編みこむ(Weave)ことができる訳です。
class FooProxy : RealProxy { //コンストラクタ public FooProxy(Type type) :base(type) { } //Invokeメソッドオーバライド public override IMessage Invoke(IMessage msg) { //型に対する全てのメッセージに対して処理を施せる } 〜以下省略 }
ところでRealProxyがメッセージの補足を確実にする為にReadProxyのコンストラクタの引数には特定の種類の型しかセットできません。許可された型以外をセットすると例外"ArgumentException"がスロウされます。RealProxyのコンストラクタ引数に指定できる型は
- MarshalByRefObject又はその派生型であること
- インタフェース(interface)であること
これらのどちらかの条件を満たしている必要がありますがこの条件に合致しない型を指定するとコンパイラの最適化やJITによるインライン化によりRealProxyのメッセージ補足がバイパスされてしまう恐れがある為です。
前置きが長くなりましたが.NETで、RealProxyを使用してAspectの編み込みを行う場合、対象の型はMarshalByRefObjectの派生又はInterfaceである必要がある訳です。拙作のDIContinerはSeasar2同様に名前、又は型によりコンポーネントの生成と参照を引くことができますが普通にコンポーネントの取得を行う場合このRealProxyの制約を満たしているか否かをチェックできないことに気がつきました。
仕方が無いのでDIContainerにおけるデプロイヤとアセンブラのメソッドにコンポーネントが要求された際の型をパラメタとして渡すようにしてその型を判定することでAspectを適用するか否かを判定することにしました。以下、IDeployerはDIContainerから呼ばれて必要であれば適切なIAssemblerインタフェースの実装を生成しコンポーネントを構成しますがメソッドに引数"type"を追加することにより構成時にAspectの編みこみが可能かどうかを判断できるようになっています。
IAssemblerは適切なコンポーネントのインスタンスを生成し設定ファイルに書かれた全てのインジェクションを処理した後に要求されている型がAOP可能かどうかを判定し必要ならばAspectのWeaveを実行します。
public interface IDeployer { ////// コンポーネントをデプロイします /// /// 要求されている型をセットします ///object デプロイされるオブジェクトの参照が戻ります object Deploy(Type type); } public interface IAssembler { ////// コンポーネントを構成します /// /// 要求されている型をセットします ///構成されたコンポーネントが戻ります object Assemble(Type type); ////// コンポーネントを構成します /// void Assemble(object component); }
思わぬ所でJavaと.NETの差が出てしまいましたがもう少し検討要かな。
#追記:このままじゃだめだ..自動バインドから考え直し