DIコンテナで生成するオブジェクトを拡張する
Kazzzの「JとNの狭間で」- DynamicProxyとリフレクションのエントリに関して、すぎもとかずやさんから早速言及頂いた。
CreateProxyの方は、DIコンテナで作成したインスタンスをそのまま拡張してくれるので、想定通りの動きをするのですが、CreateClassProxyの方はメソッド内で新しいインスタンスを作成するようでDIコンテナで作成したインスタンスを使えません。
sugimotokazuyaの日記 - DynamicProxyでProxyによる拡張前にインスタンスを生成したい
Castle.DynamicProxyは「既存の型を拡張する」方向で作られたプロキシラィブラリィなので、これはいたしかた無いと思います。また、CreateProxyが元のインスタンスを拡張できるのは、インタフェースが解っているからこそできることですね。
ということはインターフェースを持たない、もしくはインターフェース型を指定できない状況では、Proxyによる拡張の前にDIコンテナでインスタンスを作成することはできないようです。
困ったなぁ〜(^^;)
sugimotokazuyaの日記 - DynamicProxyでProxyによる拡張前にインスタンスを生成したい
これに関してですが、DIコンテナで生成したオブジェクトと、ProxyBuilder#CreateClassProxyにより生成されたオブジェクトの一意性に関してだけを問題にしているのであれば、そもそもAspectの編みこみが必要と判断されたオブジェクトに関しては、最初からDynamicProxyで拡張した型を使ってインスタンスを生成すれば良いのです。
確か、s2dotnet1.x実装ではAspectの織り込みをDeployer(デプロイヤ)で実施していたと思いますが、そのタイミングでインスタンスを拡張するのは恐らく遅すぎるのではないでしょうか。
例として掲載しますが、拙作のAbstractConstructorAssembler(コンストラクタ用アセンブラの抽象クラス)のAssembleDefault、つまりデフォルトコンストラクタによるアセンブルでは以下のように実装しています。現在、型情報のキャッシュを試みており実装はまた変わる予定ですが、s2のコミッタであれば、コードを見れば何をしているか、大体の想像は付くと思います。
protected object AssembleDefault()
{
Type type = this.ComponentDef.ComponentType;
ConstructorInfo constructor = TypeUtil.GetConstructorInfo(type, null);
object obj = TypeUtil.NewInstance(constructor, null);
if (this.ComponentDef.AspectDefSize > 0)
{
AopProxyUtil.WeaveAspect(ref obj, this.ComponentDef);
}
return obj; //戻り値のオブジェクトはDynamicProxyで拡張されている可能性がある。
}
本家Seasar2ではどうかというと、型の拡張は更に早いタイミングで行っていたはずです。
具体的には、ComponentDefインタフェース内、コンポーネントの型を格納しているcomponentTypeとは明確に区別したconcreteTypeという内部フィールドに拡張された型が格納されており、Aspectの織り込みが必要なインスタンス生成時には、ConcreteTypeつまり拡張された型からオブジェクトが生成されていたかと。
拙作のコンテナでもSeasar2と同様にする予定でしたが、そうすると今まで使用していたRealProxyを利用したAopProxyとの互換性を保てなくなったので、今の実装にしています。
ということで、この際ですからAspectの織り込みをデプロイヤからアセンブラに移してはいかがでしょうか。と、コミッタになってもいないのに提言してみます。(笑