上节谈了谈类工厂/对象查找服务,本节谈谈AOP的实现。
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
Netop.Core的AOP采用代理的实现方式。采用代理方式,您的类就必须继承一个基类(当然不是那个默认的Object,如您的类已经有一个父类,那可以让那个类的父类去继承)--
ContextBoundObject或Netop.Core.Aspect.AspectObject。当然Netop.Core.Aspect.AspectObject就是继承ContextBoundObject的。
Netop.Core的AOP处理建议接口
//AOP前处理建议
public interface IBeforeAdvisor : IAspect
{
void PreProcess(IMessage msg);
}
//AOP后处理建议
public interface IAfterAdvisor : IAspect
{
void PostProcess(IMethodReturnMessage msg);
}
//AOP异常建议(实际上就是后处理接口)
public interface IExceptionAdvisor : IAfterAdvisor
{
}
//AOP前/后均处理建议
public interface IAroundAdvisor : IBeforeAdvisor, IAfterAdvisor
{
}
Netop.Core的AOP的代理类为是继承RealProxy的Netop.Core.Aspect.AspectProxy,它要重写IMessage Invoke(IMessage msg)方法。这里顺便提一下,远程服务就是重写
RealProxy的IMessage Invoke(IMessage msg)方法实现的。当然这也是实现AOP的一种方式。
上面提了一下接口和代理类,下面先讲讲配置。还记得Netop.Core的类工厂/对象查找服务的配置吗?
<Application.ObjectLocator>
<DefaultAppObjectLocatorService>Netop.Core.LocatorService.DefaultAppObjectLocatorService,Netop.Core</DefaultAppObjectLocatorService>
<ObjectServiceAgentName>AppObjectService</ObjectServiceAgentName>
<AspectAgentName>AppAspect</AspectAgentName>
</Application.ObjectLocator>
<Application.Agent>
<Agent name="AppObjectService" type="Netop.Core.Configuration.FileAgentConfiguration,Netop.Core">
<File>Service.xml</File>
</Agent>
<Agent name="AppAspect" type="Netop.Core.Configuration.FileAgentConfiguration,Netop.Core">
<File>Aspect.xml</File>
</Agent>
</Application.Agent>
</Application.ObjectLocator>
<AspectAgentName>AppAspect</AspectAgentName>是配置AOP服务的,AppAspect名称对应于Application.Agent下节点Agent name="AppAspect"的信息:
<Agent name="AppAspect" type="Netop.Core.Configuration.FileAgentConfiguration,Netop.Core">
<File>Aspect.xml</File>
</Agent>
查看AspectConfiguration.cs文件内容,AppAspectConfigurationManager类通过调用AppObjectLocatorConfigurationManager.Current.AspectAgentName获得AspectAgentName
对应的配置代理名称,再通过调用配置代理服务得到Aspect.xml的内容。如测试程序Aspect.xml的内容为:
<Application.Aspect>
<Object name="A0" type="Test.Core.MyAdvisor,Test.Core"
isSingleton = "true" pointcut="Construction|Method|Property"
match="*,He*,*"/>
</Application.Aspect>
name:拦截器名,没有特别的含义,只要唯一就行;
type:拦截器类的全名;
isSingleton:此拦截器是否为单例,值为"true"或"1"或"yes",则为单例. 单例时可提高性能,不设置时默认为单例;
pointcut:拦截的类型,有三种:方法(Method)、构造函数(Construction)和属性(Property);多种组合用“|”隔开。
Match:匹配规则。可对类名,方法,属性定义规则。类名,方法,属性三者的规则之间用","隔开。如match="*,Get*,*"中,类名的匹配在第一个逗号前为"*",方法的匹配在第二
个逗号前为"Get*",属性的匹配在第二个逗号后为"*"。
类名的匹配:符合正则表达式匹配为真时的类;
方法的匹配:如pointcut中无Method则均不匹配; 如pointcut中有Method则为符合正则表达式匹配为真时的方法.
属性的匹配:如pointcut中无Property则均不匹配;如pointcut中有Property则为符合正则表达式匹配为真时的属性.
讲清楚了基本配置,通过测试程序来说明使用和源码解说:
namespace Test.Core
{
public interface IService : IDisposable
{
void Hello();
}
public class Service3 : AspectObject, IService
{
public void Hello()
{
Console.WriteLine("");
Console.WriteLine("Do3 begin");
Console.WriteLine("Do3 ...");
Console.WriteLine(this.GetType().FullName);
Console.WriteLine("Do3 end");
Console.WriteLine("");
}
public void Dispose()
{
Console.WriteLine("Service3:Dispose");
}
}
public class MyAdvisor : IAroundAdvisor
{
public void PreProcess(IMessage msg)
{
Console.WriteLine("PreProcess ...");
}
public void PostProcess(IMethodReturnMessage msg)
{
Console.WriteLine("PostProcess ...");
}
}
}
类Service3继承了AspectObject,拦截器类为MyAdvisor,实现了IAroundAdvisor的方法。
Aspect.xml对拦截器类MyAdvisor进行配置:
<Application.Aspect>
<Object name="A0" type="Test.Core.MyAdvisor,Test.Core" isSingleton =
"true" pointcut="Construction|Method|Property" match="*,He*,*"/>
</Application.Aspect>
Service.xml对类Service3进行配置:
<Application.ObjectService>
<Object name="A3" type="Test.Core.Service3,Test.Core" isAspect="1">
</Object>
</Application.ObjectService>
注意:增加了isAspect属性,值为"true"或"1"或"yes"时为才可能激活AOP服务通道(进入了这个通道后,真正是否执行还要看拦截器配置的匹配问题)。
当执行IService s3 =
Netop.Core.LocatorService.AppObjectLocatorManager.GetObject("A3") as
IService 时调用了DefaultAppObjectLocatorService的GetObject的方法
,当发现"A3"(Service3)的isAspect为真时,并且Service3类是继承于Netop.Core.Aspect.AspectObject(MarshalByRefObject)的,将获取一个透明代理,
DefaultAppObjectLocatorService相关的代码为:
o = TypeUtil.CreateInstance(t);
if (os.IsAspect)
{
if (o is MarshalByRefObject)
{
RealProxy realProxy = new AspectProxy(t, (MarshalByRefObject)o);
o = realProxy.GetTransparentProxy() as MarshalByRefObject;
}
}
通过自定义的RealProxy创建TransparentProxy供客户端代码调用,对于通过TransparentProxy的每一次调用,都会被RealProxy接管,这样我们在RealProxy中Invoke方法加入
的相关代码在每次调用方法时都会被调用。
AspectProxy中Invoke方法的代码就不一一细说了,主要逻辑是先获得匹配的拦截器,然后进行前处理、消息本身的处理、后处理等动作。
上面讲的激活AOP服务通道是设置isAspect属性,这是比较灵活的一种:
<Application.ObjectService>
<Object name="A3" type="Test.Core.Service3,Test.Core" isAspect="1">
</Object>
</Application.ObjectService>
另一种很不灵活的方法是不在Service.xml进行配置,而是在对应类加特性AspectAttribute,如:
[AspectAttribute]
public class Service3 : AspectObject, IService
{
public void Hello()
{
Console.WriteLine("");
Console.WriteLine("Do3 begin");
Console.WriteLine("Do3 ...");
Console.WriteLine(this.GetType().FullName);
Console.WriteLine("Do3 end");
Console.WriteLine("");
}
public void Dispose()
{
Console.WriteLine("Service3:Dispose");
}
}
这是一种选择,但不建议这样使用。感兴趣的可以看看AspectAttribute代码。
Netop.Core的AOP能很好与对象查找服务集成在一起,代码也简单,实现了微量级的目标。
轻量级的.NET对象查找服务和AOP开发框架源码Netop.Core3.5下载地址:http://download.csdn.NET/detail/tom_cat_xie_jxdy/9837303
轻量级的.NET对象查找服务和AOP开发框架测试源码 下载地址:http://download.csdn.Net/detail/tom_cat_xie_jxdy/9837278
Netop.Core--轻量级的.NET对象查找服务和AOP开发框架文档下载地址:http://download.csdn.net/detail/tom_cat_xie_jxdy/9838212