AspectSharp內建的例子提供了一個簡單的logger攔截器和一個持久化混合器. 下面來看看它的工作原理.
1. 類和介面說明:
IMessage: Message對象介面, (要實現aspect的對象必須聲明介面?)
MessageImpl: 實現IMessage介面;
IMessagePersistence: Message對象持久化介面;
LoggerInterceptor: 日誌攔截器;
MessagePersistenceMixin: Message持久混合器, 實現IMessagePersistence介面;
2. 主程式碼:
//Creating the proxy
IMessage message = AspectSharpEngine.Wrap( new MessageImpl() ) as IMessage;
message.Message = “test“;
// 注一: 顯然這個message並不是真正實現IMessage的對象, 否則將無法攔截方法.
//Casting to the persistence service
IMessagePersistence persistence = (IMessagePersistence)message;
// 注二: message對象並沒有實現IMessagePersistence介面!
persistence.Save();
看到這段代碼完全無法想像AOP是如何工作, 有點偷天換日的感覺;
關鍵就在這個proxy對象上, 先做一個這樣假設:
message.Message = “test“;
這個message肯定不是MessageImpl的執行個體, 那麼這個Message是什麼呢? 可能是個Aspect對象(aspect對象包含對象的所有攔截器和混合器). 它封裝了MessageImpl對象. 不能解釋的就是Aspect並沒有從IMessage介面繼承?
IMessagePersistence persistence = (IMessagePersistence)message;
這個比較容易理解, 雖然message並沒有實現IMessagePersistence, 但只要重載as操作就可以得到我們想要的.
3. AspectSharpEngine
看名字就知道啦, AspectSharp核心對象, 負責封裝對象.來看一下封裝對象的代碼:
public static object Wrap(object target)
{
Type originType = target.GetType();
string typeName = originType.FullName;
// 取得Invocation的處理對象, 預設為DefaultInvocationHandler
IInvocationHandler handler = GetInvocationHandler(target);
// 取得MixinInvocation的處理對象, 預設為MixinInvocationHandler
IMixinInvocationHandler mixinHandler = GetMixinInvocationHandler();
// 取得所有加在對象上的混合器, 混合器在設定檔中聲明.
IMixin[] mixins = GetMixins(typeName);
// 檢查cache
if ( !_typeCache.Contains(typeName) )
{
// 取得對象實現的介面
Type[] interfaces = GetInterfacesFrom(originType);
// 取得代理的物件類型, 注意, 這時傳入了對象實現的介面和所有混合器的介面,
// 是否會建立一個實現所有這些介面的物件類型了?
Type proxyType = ProxyGenerator.CreateProxyType(interfaces, mixins);
_typeCache.Add( typeName, proxyType );
}
// 返回已封裝對象的執行個體.
return ProxyGenerator.CreateInstance(
_typeCache[typeName], mixins, handler, mixinHandler );
}
4. ProxyGenerator
負責建立代理對象的類型和執行個體.
/// Generates a proxy transient Type implementing all the specified interfaces and mixins
/// redirecting method invocations to the specifed handler.
上面這段是CreateProxyType方法的描述, 如我所想, 確實要建立一個實現所有介面的代理對象. Year! 有點佩服自己了. (有東西就扔過來吧, 呵呵.)
internal static Type CreateProxyType(Type[] interfaces, IMixin[] mixins)
{
// ...
// 建立一個程式集
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "DynamicAssemblyProxyGen";
// 定義動態程式集
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder =
assemblyBuilder.DefineDynamicModule( assemblyName.Name, true );
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"ProxyType", TypeAttributes.Public|TypeAttributes.Class, null, MergeTypes(interfaces, mixins) );
FieldBuilder handlerField = GenerateField( typeBuilder, handlerFieldName, typeof(IInvocationHandler) );
FieldBuilder mixinHandlerField = GenerateField( typeBuilder, mixinHandlerFieldName, typeof(IMixinInvocationHandler) );
FieldBuilder mixinsField = GenerateField( typeBuilder, "mixins", typeof(IMixin[]) );
ConstructorBuilder constr = GenerateConstructor( typeBuilder, handlerField, mixinsField, mixinHandlerField );
GenerateInterfaceImplementation( typeBuilder, interfaces, handlerField ); GenerateMixinImplementation
( typeBuilder, mixins, mixinHandlerField, mixinsField);
return typeBuilder.CreateType();
}
以上代碼看的頭有點大, 請參考.net sdk,
只要知道此方法建立一個實現所有介面的物件類型就好了.
public static object CreateInstance(Type type, IMixin[] mixins,
IInvocationHandler handler, IMixinInvocationHandler mixinHandler)
{
return Activator.CreateInstance( type, new object[]{ handler, mixinHandler, mixins} );
}
直接建立一個執行個體, 這個對象的類型就是在CreateProxyType中動態加入的. 不是Aspect. 判斷錯誤!.
看來頭大也要把CreateProxyType的代碼弄清楚了. 不過有個疑問, 動態建立的建構函式如何加入代碼?
5 設定檔
設定檔內容比較簡單.
<advices>
<interceptors>
// 定義攔截器
<interceptor type="AspectSharp.Sample.Interceptor.LoggerInterceptor, AspectSharp.Sample" name="Logger" />
</interceptors>
<mixins>
// 定義混合器
<mixin type="AspectSharp.Sample.Mixin.MessagePersistenceMixin, AspectSharp.Sample" name="Persistence" />
</mixins>
</advices>
<aspects defaultNamespace="AspectSharp.Sample">
// 聲明要aspect的對象和混合器
<aspect mixin="Persistence" namespace="Model" typeName="MessageImpl">
// 要攔截的對象,
<pointcut interceptor="Logger" method="set" />
</aspect>
</aspects>
顯然, AOP的關鍵就在那個動態建立的實現所有介面的代理對象上,
但是這個代理對象是如何與我們定義的攔截器和混合器互動的呢? 請關注後續文章.