上節談了談類工廠/對象查找服務,本節談談AOP的實現。 AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程,通過預編譯方式和運行期動態代理實現程式功能的統一維護的一種技術。 Netop.Core的AOP採用代理的實現方式。採用代理方式,您的類就必須繼承一個基類( ...
上節談了談類工廠/對象查找服務,本節談談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