日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自己实现简单的AOP(三) 实现增强四项基本功能

發布時間:2024/1/17 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己实现简单的AOP(三) 实现增强四项基本功能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面的兩篇隨筆,都是只是個鋪墊,真正實現增強四項基本功能的重頭戲,在本篇隨筆中,

本文將通過AOP實現如下的四個基本功能:

/// <para>1、自動管理數據庫連接[可選]</para>
/// <para>2、自動管理數據庫事務,當接收到異常后(無論什么異常)事務將自動回滾[可選]</para>
/// <para>3、服務級加鎖[必選]</para>
/// <para>4、以統一方式處理 服務異常 及 錯誤, 包括數據庫異常 和 主動拋出的異常[必選]</para>

?

為了在完成3、4兩項,需要在Service層基類中,引入幾個屬性和方法,以便協作完成相應功能。

該Service基類,很簡單,不用太多的解釋:

/// <summary>/// 擴展的抽象服務類/// <para>配合增強類,完成以下功能:</para>/// <para>1、自動管理數據庫連接[可選]</para>/// <para>2、自動管理數據庫事務,當接收到異常后(無論什么異常)事務將自動回滾[可選]</para>/// /// <para>3、服務級加鎖[必選]</para>/// <para>4、以統一方式處理服務異常及錯誤處理,包括數據庫異常 和 主動拋出的異常[必選]</para>/// </summary>public abstract class ServiceAbstract : MarshalByRefObject{/// <summary>/// 是否發生錯誤/// </summary>public bool Error { get; protected set; }/// <summary>/// 錯誤提示信息(友好的,用戶可見)/// </summary>public string ErrorMsg { get; protected set; }/// <summary>/// 錯誤詳情/// <para>所有錯誤,均通過異常拋出</para>/// </summary>public Exception ErrorEx { get; protected set; }/// <summary>/// 重置錯誤信息/// </summary>public void ResetError(){this.Error = false;this.ErrorMsg = string.Empty;this.ErrorEx = null;}/// <summary>/// 設置錯誤信息/// </summary>/// <param name="msg"></param>/// <param name="ex"></param>public void SetError(string msg, Exception ex){this.Error = true;this.ErrorEx = ex;this.ErrorMsg = msg;}/// <summary>/// 獲取服務級別的鎖定對象,以完成系統應用層加鎖(具體而言是Service層加鎖)/// </summary>/// <returns></returns>public abstract object GetLockObject();} Service基類

?

為了統一處理錯誤,引入一自定義異常,所有需要拋出錯誤的地方,都拋出該異常即可。

/// <summary>/// 自定義的服務異常/// </summary> [Serializable]public class ServiceException : Exception{/// <summary>/// 為異常提供附加數據/// <para>用戶不可見</para>/// </summary>public int Code { get; set; }/// <summary>/// 為異常提供附加數據/// <para>用戶不可見</para>/// </summary>public string Tag { get; set; }public ServiceException() { }public ServiceException(string message) : base(message) { }public ServiceException(string message, Exception inner) : base(message, inner) { }protected ServiceException(System.Runtime.Serialization.SerializationInfo info,System.Runtime.Serialization.StreamingContext context): base(info, context) { }} 自定義異常

?

重頭戲:抽象的增強類:

/// <summary>/// 抽象的服務增強類/// <para>增強以下功能:</para>/// <para>1、自動管理數據庫連接[可選]</para>/// <para>2、自動管理數據庫事務,當接收到異常后(無論什么異常)事務將自動回滾[可選]</para>/// /// <para>3、服務級加鎖[必選]</para>/// <para>4、以統一方式處理 服務異常 及 錯誤, 包括數據庫異常 和 主動拋出的異常[必選]</para>/// </summary>public abstract class ServiceAdviceAbstract<T> : AdviceAbstract where T : Exception{private static object objLock = new object();#region 屬性/// <summary>/// 是否保持(長)連接,即自動管理連接/// </summary>public bool KeepConnection { get; private set; }/// <summary>/// 是否使用事務,即自動管理事務/// </summary>public bool UseTransaction { get; private set; }/// <summary>/// 是否在當前方法的增強中打開了連接/// </summary>protected bool CurrentKeepConnection { get; set; }/// <summary>/// 是否在當前方法的增強中開啟了事務/// </summary>protected bool CurrentUseTransaction { get; set; }#endregion#region 構造函數/// <summary>/// /// </summary>/// <param name="keepConnection">是否保持(長)連接,即自動管理連接</param>/// <param name="useTransaction">是否使用事務,即自動管理事務</param>public ServiceAdviceAbstract(bool keepConnection, bool useTransaction){this.KeepConnection = keepConnection;this.UseTransaction = useTransaction;}#endregionpublic sealed override IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage){ServiceAbstract service = target as ServiceAbstract;// 服務類型校驗 其拋出的異常不會被捕獲 Check(service);return LockInvoke(service, callMessage);}#region 可以擴展的虛函數/// <summary>/// 執行Lock加鎖調用/// </summary>/// <param name="target"></param>/// <param name="callMessage"></param>/// <returns></returns>protected virtual IMessage LockInvoke(ServiceAbstract target, IMethodCallMessage callMessage){lock (target.GetLockObject()){return CatchAdviceInvoke(target, callMessage);}}/// <summary>/// 執行Try...Catch增強調用/// </summary>/// <param name="target"></param>/// <param name="callMessage"></param>/// <returns></returns>protected virtual IMessage CatchAdviceInvoke(ServiceAbstract target, IMethodCallMessage callMessage){try{BeforeInvokeBeProxy(target);IMessage message = DelayProxyUtil.InvokeBeProxy(target, callMessage);AfterInvokeBeProxy(target);return message;}// 調用方法時,內部拋出的異常catch (TargetInvocationException targetEx){string msg = string.Empty;if (!(targetEx.InnerException is ServiceException)){if (targetEx.InnerException is DbException){msg = "數據異常:";}else if (targetEx.InnerException is T){msg = "服務異常:";}else{msg = "系統異常:";}}return ReturnError(msg + targetEx.InnerException.Message, targetEx.InnerException, target, callMessage);}catch (ServiceException sEx){return ReturnError(sEx.Message, sEx, target, callMessage);}catch (DbException dbEx){return ReturnError("數據異常:" + dbEx.Message, dbEx, target, callMessage);}catch (T tEx){return ReturnError("服務異常:" + tEx.Message, tEx, target, callMessage);}catch (Exception ex){return ReturnError("系統異常:" + ex.Message, ex, target, callMessage);}}/// <summary>/// 調用被代理對象方法前執行/// </summary>/// <param name="target"></param>protected virtual void BeforeInvokeBeProxy(ServiceAbstract target){target.ResetError();this.CurrentKeepConnection = false;this.CurrentUseTransaction = false;if (!this.KeepConnection && !this.UseTransaction){return;}// 已經開啟了事務 if (this.HasBeginTransaction()){// 不需要在當前方法的增強中進行任何處理return;}// 已經打開了連接if (this.HasOpenConnection()){if (this.UseTransaction){this.BeginTransaction(true);this.CurrentUseTransaction = true;return;}return;}// 即沒有開啟事務,又沒有打開連接if (this.UseTransaction){this.BeginTransaction(false);this.CurrentKeepConnection = true;this.CurrentUseTransaction = true;}else if (this.KeepConnection){this.OpenConnection();this.CurrentKeepConnection = true;}}/// <summary>/// 調用被代理對象方法后執行/// </summary>/// <param name="target"></param>protected virtual void AfterInvokeBeProxy(ServiceAbstract target){// 當前增強 只打開了連接if (this.CurrentKeepConnection && !this.CurrentUseTransaction){this.CloseConnection();}// 當前增強 只開啟了事務else if (!this.CurrentKeepConnection && this.CurrentUseTransaction){this.CommitTransaction(true);}// 當前增強 既打開了連接,又開啟了事務else if (this.CurrentKeepConnection && this.CurrentUseTransaction){this.CommitTransaction(false);}}/// <summary>/// 返回錯誤信息/// <para>攔截所有異常,將錯誤信息存儲到 ExtensionServiceAbstract 對象中,并返回被調用方法的默認值</para>/// </summary>/// <param name="msg"></param>/// <param name="ex"></param>/// <param name="target"></param>/// <param name="callMessage"></param>/// <returns></returns>protected virtual IMessage ReturnError(string msg, Exception ex,ServiceAbstract target, IMethodCallMessage callMessage){try{// 當前增強 只打開了連接if (this.CurrentKeepConnection && !this.CurrentUseTransaction){this.CloseConnection();}// 當前增強 只開啟了事務else if (!this.CurrentKeepConnection && this.CurrentUseTransaction){this.RollBackTransaction(true);}// 當前增強 既打開了連接,又開啟了事務else if (this.CurrentKeepConnection && this.CurrentUseTransaction){this.RollBackTransaction(false);}}catch (Exception e){Console.WriteLine(e.Message);}// 如果 邏輯上下文中已經進行了Try...Catch調用,// 則 將捕獲的異常向上層拋出//if (this.HasTryCatch)//{// return DelayProxyUtil.ReturnExecption(ex, callMessage);//} target.SetError(msg, ex);// 記錄日志 WriteLog(ex);return DelayProxyUtil.ReturnDefaultValue(target, callMessage);}/// <summary>/// 記錄日志/// </summary>/// <param name="ex"></param>protected virtual void WriteLog(Exception ex){}/// <summary>/// 校驗被代理的對象的類型/// </summary>/// <param name="service"></param>protected virtual void Check(ServiceAbstract service){if (service == null){throw new ServiceException("服務增強類 AdviceAbstractGeneric 只能用于 MyBatisServiceAbstract類型的子類型 ");}}#endregion#region 管理數據庫連接和事務/// <summary>/// 打開連接/// </summary>protected abstract void OpenConnection();/// <summary>/// 關閉連接/// </summary>protected abstract void CloseConnection();/// <summary>/// 開啟事務/// </summary>protected abstract void BeginTransaction(bool onlyBeginTransaction);/// <summary>/// 提交事務/// </summary>protected abstract void CommitTransaction(bool onlyCommitTransaction);/// <summary>/// 回滾事務/// </summary>protected abstract void RollBackTransaction(bool onlyRollBackTransaction);/// <summary>/// 是否打開了連接/// </summary>/// <returns></returns>protected abstract bool HasOpenConnection();/// <summary>/// 是否開啟了事務/// </summary>/// <returns></returns>protected abstract bool HasBeginTransaction();#endregion} 抽象的增強類

?

雖然,該類是抽象類,但四項基本功能,都已經完成了。

?

另外,需要指出一點潛在bug:

當Service方法嵌套調用Service方法的時候,如果內層Service方法,拋出了異常,

會被內層方法的增強所捕獲,而外層Service方法接收不到錯誤信息。

正因如此,可能外層方法的事務無法像預料的那樣進行回滾。

當然,解決該問題,相對而言也算簡單,下篇隨筆再做說明。

?

還有一點需要說明:

我當前的增強是基于iBatisNet的,其數據庫操作都是基于單例模式實現的(借助了HttpContext),

所以我將數據庫連接及事務管理的相關方法,放在了‘增強繼承體系’中,

如果使用其他方式處理數據庫連接或事務,比較麻煩、可以考慮將相關方法,遷移到‘Service基類中’,放入‘Service繼承體系’。

借用Service層,連接Dao層,實現真正的數據庫操作(包括 連接 和 事務)。

具體的實現方式,就留給大家去探究了。

?

附源碼(MVC4的項目 沒有packages文件夾):http://files.cnblogs.com/files/08shiyan/AOPDemo.zip?

該源碼中,沒有針對當前隨筆,做相應的 demo.?

?

未完待續...

下篇隨筆,將實現簡單的屬性注入 及 被代理對象延遲初始化。

?

總結

以上是生活随笔為你收集整理的自己实现简单的AOP(三) 实现增强四项基本功能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。