標籤:aop 代理
AOP概念
Aspect Oriented Programming,面向切面編程,可以通過先行編譯方式和運行期動態代理,實現在不修改原始碼的情況下給程式動態統一添加功能的一種技術。
前提
下面我們結合一個具體的例子來瞭解AOP。
基本情景
User類
/// <summary> /// 使用者實體,具有姓名和年齡兩個屬性 /// </summary> public class User { public string Name { get; set; } public int Age { get; set; } }
IUserService
public interface IUserService { //獲得使用者資訊 void GetUserInfo(User enUser); }
UserService
public class UserService:IUserService { /// <summary> /// 獲得使用者的資訊 /// </summary> /// <param name="enUser">使用者實體</param> public void GetUserInfo(User enUser) { //輸出使用者的姓名和年齡 Console.WriteLine("姓名:"+enUser .Name+"年齡:"+enUser .Age ); } }
用戶端(控制台應用程式)Program
- “ new()”出具體的實現——這裡我們不採用此方式
class Program { static void Main(string[] args) { //執行個體化一個實體 User enUser = new User() { Name = "Danny", Age = 15 }; IUserService userService = new UserService(); userService.GetUserInfo(enUser); } }
- 通過Spring IOC獲得具體實現(相當於工廠)
//引入Spring.Core.dllusing Spring.Context;using Spring.Context.Support;namespace WithoutAOP{ class Program { static void Main(string[] args) { //執行個體化一個實體 User enUser = new User() { Name = "Danny", Age = 15 }; //獲得Spring.IOC容器的上下文 IApplicationContext context = ContextRegistry.GetContext(); //根據設定檔中的配置獲得業務實作類別 IUserService userService = (IUserService)context.GetObject("userService"); //調用業務實作類別的方法 userService.GetUserInfo(enUser); } }}
設定檔
<!--Spring配置--> <configSections> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/> </sectionGroup> </configSections> <spring> <context> <resource uri="config://spring/objects"/> </context> <objects xmlns="http://www.springframework.net"> <object id="userService" type="AOPExample.UserService,AOPExample"/> </objects> </spring>
現在我們要為已有的商務邏輯增加日誌功能。接下來看看AOP如何來實現。
在瞭解之前,我們先來瞭解AOP中的一些術語。
AOP術語
- 目標對象(Target),即我們要代理的對象(UserService),也就是我們要為此對象增加日誌功能。
- 關注點(Concern):如日誌功能。日誌功能是系統層級的,不可能只在一個對象中增加日誌功能。
- 通知(Advice):在Advice中寫日誌功能的具體實現。通知類實現不同的介面,如:Before,After……這些決定了日誌功能如何添加(切入)到商務邏輯中,是在商務邏輯執行前添加,還是執行後添加。
AOP實現思路
- 寫具體的通知類Advice(實現日誌功能)
-
在設定檔中進行配置
ProxyFactoryObject 顯式建立AOP代理
Advice通知類
//引入System.Aop.dll;using Spring.Aop; //AOPusing System.Reflection;//反射namespace AOPExample{ /// <summary> /// Advice通知類:實現日誌功能 /// </summary> public class LogBeforeAdvice:IMethodBeforeAdvice { /// <summary> /// 實現介面IMethodBeforeAdvice中的Before方法,在目標方法執行前執行Before() /// </summary> /// <param name="method">攔截的方法</param> /// <param name="args">方法的參數</param> /// <param name="target">攔截的對象</param> public void Before(MethodInfo method, object[] args, object target) { Console.WriteLine("攔截的方法名—>" + method.Name); Console.WriteLine("目標對象—>" + target); Console.WriteLine("參數—>"); //如果參數不為空白,遍曆所有參數並輸出 if (args != null) { foreach (object arg in args) { Console.WriteLine("\t: " + arg); } } } }}
設定檔
<?xml version="1.0"?><configuration> <!--Spring.Context.Support.ContextRegistry 的類型初始值設定項引發異常。--> <!--注釋掉此配置節,否則會報上述異常--> <!--<startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" /> </startup>--> <!--Spring配置--> <configSections> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/> </sectionGroup> </configSections> <spring> <context> <resource uri="config://spring/objects"/> </context> <objects xmlns="http://www.springframework.net"> <!--配置通知類LogBeforeAdvice--> <object id="beforeAdvice" type="AOPExample.LogBeforeAdvice,AOPExample"/> <!--通過ProxyFactoryObject 顯式建立AOP代理--> <object id="userServiceProxy" type="Spring.Aop.Framework.ProxyFactoryObject"> <!--指定代理的真實對象--> <property name="Target"> <object type="AOPExample.UserService,AOPExample"/> </property> <!--指定具體通知類--> <property name="InterceptorNames"> <list> <!--指定具體通知類,和前面配置的id一致--> <value>beforeAdvice</value> </list> </property> </object> </objects> </spring></configuration>
用戶端
class Program { static void Main(string[] args) { //執行個體化使用者 User enUser = new User() { Name ="Jenny", Age=15 }; //獲得Spring容器上下文 IApplicationContext context = ContextRegistry.GetContext(); //從設定檔獲得由ProxyFactoryObject產生的代理類 //需要修改用戶端,原來是直接調用真實對象,現在是調用代理 IUserService userServiceProxy = (IUserService)context["userServiceProxy"]; userServiceProxy.GetUserInfo(enUser); } }
運行結果
總結
- 優點:通過ProxyFactoryObject 建立代理類,省去自己手動建立代理類;
- 缺點1:如果有多個目標對象,每個都需要在設定檔中配置;
- 缺點2:用戶端調用時,由原來調用目標對象,變成調用代理對象,需要修改用戶端代碼。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
AOP系列(一)——ProxyFactoryObject 顯式建立AOP代理