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的关键就在那个动态建立的实现所有接口的代理对象上,
但是这个代理对象是如何与我们定义的拦截器和混合器交互的呢? 请关注后续文章.