亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

自己實現簡單的AOP(三)實現增強四項基本功能

2019-11-14 15:48:59
字體:
來源:轉載
供稿:網友

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

本文將通過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;        }        #endregion        public 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.VEVb.com/files/08shiyan/AOPDemo.zip 

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

 

未完待續...

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

 


上一篇:WinDbg調試.NET程序入門

下一篇:幾個月

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91po在线观看91精品国产性色| 国产深夜精品福利| 色综合久久久888| 91精品免费看| 成人免费在线网址| 久久精品国产91精品亚洲| 国产精品美女主播| 国产视频在线观看一区二区| 理论片在线不卡免费观看| 福利精品视频在线| 日韩成人中文字幕| 日韩在线免费观看视频| 91精品国产一区| 亚洲开心激情网| 国产日韩欧美影视| 日韩免费中文字幕| 亚洲精品久久在线| 精品国产一区二区三区四区在线观看| 日韩在线观看免费全集电视剧网站| 亚洲一区二区三区视频播放| 欧美在线免费看| 97精品久久久中文字幕免费| 久久99热精品| 国产精品一区二区三区成人| 国产亚洲精品久久久久久777| 国产精品欧美激情在线播放| 亚洲а∨天堂久久精品9966| 色偷偷av一区二区三区乱| 成人免费看黄网站| 亚洲精品欧美极品| 国产z一区二区三区| 欧美裸体男粗大视频在线观看| 久久天天躁狠狠躁夜夜躁| 久久久精品亚洲| 久久久久五月天| 亚洲一区二区三区四区视频| 91精品在线国产| 91亚洲国产精品| 97国产精品人人爽人人做| 亚洲欧美999| 这里只有精品视频在线| 午夜精品久久久久久久久久久久| 国产午夜精品视频免费不卡69堂| 国产精品91免费在线| 免费91麻豆精品国产自产在线观看| 精品自拍视频在线观看| 亚洲天堂男人天堂女人天堂| 日韩欧美一区视频| 国产精品美女午夜av| 日韩在线视频免费观看高清中文| 日韩www在线| 国产精品亚洲第一区| 欧美性资源免费| 国产福利精品视频| 久久国产一区二区三区| 中文字幕无线精品亚洲乱码一区| 亚洲精品美女视频| 欧美在线视频a| 91国内产香蕉| 色99之美女主播在线视频| 亚洲国产精品悠悠久久琪琪| 欧美国产在线电影| 国产精品中文久久久久久久| 欧美激情国产高清| 精品露脸国产偷人在视频| 国产精品三级网站| 欧美日韩成人黄色| 欧美裸体xxxxx| 成人亚洲欧美一区二区三区| 亚洲欧美日韩精品久久| 91在线观看免费| 久久久久久久爱| 久久99久久99精品免观看粉嫩| 欧美精品一区二区三区国产精品| 国产一区二区三区视频| 色偷偷av一区二区三区乱| 亚洲视频专区在线| 中文字幕在线观看日韩| 国产精品18久久久久久麻辣| 欧美精品videosex极品1| 亚洲精品国产精品乱码不99按摩| 精品国产区一区二区三区在线观看| 亚洲剧情一区二区| 国产精品三级久久久久久电影| 在线看日韩av| 91在线免费看网站| 国产精品1区2区在线观看| 亚洲国产三级网| 亚洲欧美成人网| 国产精自产拍久久久久久| 久久影院资源站| 国产精品亚洲欧美导航| 国产伦精品一区二区三区精品视频| 一本一道久久a久久精品逆3p| 久久亚洲精品一区二区| 日韩电影免费在线观看中文字幕| 日韩欧美国产骚| 欧美日韩日本国产| 亚洲欧美在线免费| 自拍视频国产精品| 成人a在线观看| 亚洲精品一区中文字幕乱码| 日本精品一区二区三区在线播放视频| 欧洲成人性视频| 日韩精品999| 亚洲精品国产精品国产自| 亚洲欧美国产一区二区三区| 欧美午夜精品久久久久久浪潮| 欧美成人免费一级人片100| 国产精品r级在线| 精品亚洲aⅴ在线观看| 亚洲人精品午夜在线观看| 亚洲成avwww人| 久久色精品视频| www.99久久热国产日韩欧美.com| 国内外成人免费激情在线视频| 国产福利视频一区| 国产成人精彩在线视频九色| 韩国精品美女www爽爽爽视频| 亚洲国产日韩一区| 日韩视频第一页| 欧美性受xxxx白人性爽| 国产欧美精品va在线观看| 国产精品视频网| 亚洲一区二区三| 久久久久久国产精品久久| 中文日韩在线观看| 日韩精品视频观看| 国产精品成久久久久三级| 91精品中文在线| 午夜精品一区二区三区在线| 亚洲电影第1页| 亚洲伊人久久大香线蕉av| 国产小视频国产精品| 国产精品6699| 欧美夜福利tv在线| 亚洲老板91色精品久久| 欧美在线亚洲一区| 一区二区三区日韩在线| 久久久精品一区二区| 亚洲天堂av在线播放| 亚洲精品av在线播放| 色琪琪综合男人的天堂aⅴ视频| 国产一区二区三区在线观看视频| 日韩电影网在线| 在线观看国产精品91| 国产精品丝袜一区二区三区| 最近2019中文字幕大全第二页| 九九热精品视频在线播放| 中文字幕综合在线| 国产精品91在线| 日韩大胆人体377p| 亚洲天堂成人在线视频| 亚洲天堂久久av| 欧美日韩在线一区| 日本成人免费在线| 国产日韩视频在线观看| 欧美高清自拍一区| 大桥未久av一区二区三区| 欧美激情视频一区二区三区不卡| 懂色av中文一区二区三区天美| 最新日韩中文字幕| 伦伦影院午夜日韩欧美限制| 国产在线播放91|