国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

自己實(shí)現(xiàn)簡(jiǎn)單的AOP(三)實(shí)現(xiàn)增強(qiáng)四項(xiàng)基本功能

2019-11-14 15:48:59
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前面的兩篇隨筆,都是只是個(gè)鋪墊,真正實(shí)現(xiàn)增強(qiáng)四項(xiàng)基本功能的重頭戲,在本篇隨筆中,

本文將通過(guò)AOP實(shí)現(xiàn)如下的四個(gè)基本功能:

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

 

為了在完成3、4兩項(xiàng),需要在Service層基類中,引入幾個(gè)屬性和方法,以便協(xié)作完成相應(yīng)功能。

該Service基類,很簡(jiǎn)單,不用太多的解釋:

    /// <summary>    /// 擴(kuò)展的抽象服務(wù)類    /// <para>配合增強(qiáng)類,完成以下功能:</para>    /// <para>1、自動(dòng)管理數(shù)據(jù)庫(kù)連接[可選]</para>    /// <para>2、自動(dòng)管理數(shù)據(jù)庫(kù)事務(wù),當(dāng)接收到異常后(無(wú)論什么異常)事務(wù)將自動(dòng)回滾[可選]</para>    ///     /// <para>3、服務(wù)級(jí)加鎖[必選]</para>    /// <para>4、以統(tǒng)一方式處理服務(wù)異常及錯(cuò)誤處理,包括數(shù)據(jù)庫(kù)異常 和 主動(dòng)拋出的異常[必選]</para>    /// </summary>    public abstract class ServiceAbstract : MarshalByRefObject    {        /// <summary>        /// 是否發(fā)生錯(cuò)誤        /// </summary>        public bool Error { get; PRotected set; }        /// <summary>        /// 錯(cuò)誤提示信息(友好的,用戶可見(jiàn))        /// </summary>        public string ErrorMsg { get; protected set; }        /// <summary>        /// 錯(cuò)誤詳情        /// <para>所有錯(cuò)誤,均通過(guò)異常拋出</para>        /// </summary>        public Exception ErrorEx { get; protected set; }        /// <summary>        /// 重置錯(cuò)誤信息        /// </summary>        public void ResetError()        {            this.Error = false;            this.ErrorMsg = string.Empty;            this.ErrorEx = null;        }        /// <summary>        /// 設(shè)置錯(cuò)誤信息        /// </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>        /// 獲取服務(wù)級(jí)別的鎖定對(duì)象,以完成系統(tǒng)應(yīng)用層加鎖(具體而言是Service層加鎖)        /// </summary>        /// <returns></returns>        public abstract object GetLockObject();    }
Service基類

 

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

    /// <summary>    /// 自定義的服務(wù)異常    /// </summary>    [Serializable]    public class ServiceException : Exception    {        /// <summary>        /// 為異常提供附加數(shù)據(jù)        /// <para>用戶不可見(jiàn)</para>        /// </summary>        public int Code { get; set; }        /// <summary>        /// 為異常提供附加數(shù)據(jù)        /// <para>用戶不可見(jiàn)</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) { }    }
自定義異常

 

重頭戲:抽象的增強(qiáng)類:

    /// <summary>    /// 抽象的服務(wù)增強(qiáng)類    /// <para>增強(qiáng)以下功能:</para>    /// <para>1、自動(dòng)管理數(shù)據(jù)庫(kù)連接[可選]</para>    /// <para>2、自動(dòng)管理數(shù)據(jù)庫(kù)事務(wù),當(dāng)接收到異常后(無(wú)論什么異常)事務(wù)將自動(dòng)回滾[可選]</para>    ///     /// <para>3、服務(wù)級(jí)加鎖[必選]</para>    /// <para>4、以統(tǒng)一方式處理 服務(wù)異常 及 錯(cuò)誤, 包括數(shù)據(jù)庫(kù)異常 和 主動(dòng)拋出的異常[必選]</para>    /// </summary>    public abstract class ServiceAdviceAbstract<T> : AdviceAbstract where T : Exception    {        private static object objLock = new object();        #region 屬性        /// <summary>        /// 是否保持(長(zhǎng))連接,即自動(dòng)管理連接        /// </summary>        public bool KeepConnection { get; private set; }        /// <summary>        /// 是否使用事務(wù),即自動(dòng)管理事務(wù)        /// </summary>        public bool UseTransaction { get; private set; }        /// <summary>        /// 是否在當(dāng)前方法的增強(qiáng)中打開(kāi)了連接        /// </summary>        protected bool CurrentKeepConnection { get; set; }        /// <summary>        /// 是否在當(dāng)前方法的增強(qiáng)中開(kāi)啟了事務(wù)        /// </summary>        protected bool CurrentUseTransaction { get; set; }        #endregion        #region 構(gòu)造函數(shù)        /// <summary>        ///         /// </summary>        /// <param name="keepConnection">是否保持(長(zhǎng))連接,即自動(dòng)管理連接</param>        /// <param name="useTransaction">是否使用事務(wù),即自動(dòng)管理事務(wù)</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;            // 服務(wù)類型校驗(yàn) 其拋出的異常不會(huì)被捕獲            Check(service);            return LockInvoke(service, callMessage);        }        #region 可以擴(kuò)展的虛函數(shù)        /// <summary>        /// 執(zhí)行Lock加鎖調(diào)用        /// </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>        /// 執(zhí)行Try...Catch增強(qiáng)調(diào)用        /// </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;            }            // 調(diào)用方法時(shí),內(nèi)部拋出的異常            catch (TargetInvocationException targetEx)            {                string msg = string.Empty;                if (!(targetEx.InnerException is ServiceException))                {                    if (targetEx.InnerException is DbException)                    {                        msg = "數(shù)據(jù)異常:";                    }                    else if (targetEx.InnerException is T)                    {                        msg = "服務(wù)異常:";                    }                    else                    {                        msg = "系統(tǒng)異常:";                    }                }                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("數(shù)據(jù)異常:" + dbEx.Message, dbEx, target, callMessage);            }            catch (T tEx)            {                return ReturnError("服務(wù)異常:" + tEx.Message, tEx, target, callMessage);            }            catch (Exception ex)            {                return ReturnError("系統(tǒng)異常:" + ex.Message, ex, target, callMessage);            }        }        /// <summary>        /// 調(diào)用被代理對(duì)象方法前執(zhí)行        /// </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;            }            // 已經(jīng)開(kāi)啟了事務(wù)                        if (this.HasBeginTransaction())            {                // 不需要在當(dāng)前方法的增強(qiáng)中進(jìn)行任何處理                return;            }            // 已經(jīng)打開(kāi)了連接            if (this.HasOpenConnection())            {                if (this.UseTransaction)                {                    this.BeginTransaction(true);                    this.CurrentUseTransaction = true;                    return;                }                return;            }            // 即沒(méi)有開(kāi)啟事務(wù),又沒(méi)有打開(kāi)連接            if (this.UseTransaction)            {                this.BeginTransaction(false);                this.CurrentKeepConnection = true;                this.CurrentUseTransaction = true;            }            else if (this.KeepConnection)            {                this.OpenConnection();                this.CurrentKeepConnection = true;            }        }        /// <summary>        /// 調(diào)用被代理對(duì)象方法后執(zhí)行        /// </summary>        /// <param name="target"></param>        protected virtual void AfterInvokeBeProxy(ServiceAbstract target)        {            // 當(dāng)前增強(qiáng) 只打開(kāi)了連接            if (this.CurrentKeepConnection && !this.CurrentUseTransaction)            {                this.CloseConnection();            }            // 當(dāng)前增強(qiáng) 只開(kāi)啟了事務(wù)            else if (!this.CurrentKeepConnection && this.CurrentUseTransaction)            {                this.CommitTransaction(true);            }            // 當(dāng)前增強(qiáng) 既打開(kāi)了連接,又開(kāi)啟了事務(wù)            else if (this.CurrentKeepConnection && this.CurrentUseTransaction)            {                this.CommitTransaction(false);            }        }        /// <summary>        /// 返回錯(cuò)誤信息        /// <para>攔截所有異常,將錯(cuò)誤信息存儲(chǔ)到 ExtensionServiceAbstract 對(duì)象中,并返回被調(diào)用方法的默認(rèn)值</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            {                // 當(dāng)前增強(qiáng) 只打開(kāi)了連接                if (this.CurrentKeepConnection && !this.CurrentUseTransaction)                {                    this.CloseConnection();                }                // 當(dāng)前增強(qiáng) 只開(kāi)啟了事務(wù)                else if (!this.CurrentKeepConnection && this.CurrentUseTransaction)                {                    this.RollBackTransaction(true);                }                // 當(dāng)前增強(qiáng) 既打開(kāi)了連接,又開(kāi)啟了事務(wù)                else if (this.CurrentKeepConnection && this.CurrentUseTransaction)                {                    this.RollBackTransaction(false);                }            }            catch (Exception e)            {                Console.WriteLine(e.Message);            }            // 如果 邏輯上下文中已經(jīng)進(jìn)行了Try...Catch調(diào)用,            // 則   將捕獲的異常向上層拋出            //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>        /// 校驗(yàn)被代理的對(duì)象的類型        /// </summary>        /// <param name="service"></param>        protected virtual void Check(ServiceAbstract service)        {            if (service == null)            {                throw new ServiceException("服務(wù)增強(qiáng)類 AdviceAbstractGeneric 只能用于 MyBatisServiceAbstract類型的子類型 ");            }        }        #endregion        #region 管理數(shù)據(jù)庫(kù)連接和事務(wù)        /// <summary>        /// 打開(kāi)連接        /// </summary>        protected abstract void OpenConnection();        /// <summary>        /// 關(guān)閉連接        /// </summary>        protected abstract void CloseConnection();        /// <summary>        /// 開(kāi)啟事務(wù)        /// </summary>        protected abstract void BeginTransaction(bool onlyBeginTransaction);        /// <summary>        /// 提交事務(wù)        /// </summary>        protected abstract void CommitTransaction(bool onlyCommitTransaction);        /// <summary>        /// 回滾事務(wù)        /// </summary>        protected abstract void RollBackTransaction(bool onlyRollBackTransaction);        /// <summary>        /// 是否打開(kāi)了連接        /// </summary>        /// <returns></returns>        protected abstract bool HasOpenConnection();        /// <summary>        /// 是否開(kāi)啟了事務(wù)        /// </summary>        /// <returns></returns>        protected abstract bool HasBeginTransaction();        #endregion    }
抽象的增強(qiáng)類

 

雖然,該類是抽象類,但四項(xiàng)基本功能,都已經(jīng)完成了。

 

另外,需要指出一點(diǎn)潛在bug:

當(dāng)Service方法嵌套調(diào)用Service方法的時(shí)候,如果內(nèi)層Service方法,拋出了異常,

會(huì)被內(nèi)層方法的增強(qiáng)所捕獲,而外層Service方法接收不到錯(cuò)誤信息。

正因如此,可能外層方法的事務(wù)無(wú)法像預(yù)料的那樣進(jìn)行回滾。

當(dāng)然,解決該問(wèn)題,相對(duì)而言也算簡(jiǎn)單,下篇隨筆再做說(shuō)明。

 

還有一點(diǎn)需要說(shuō)明:

我當(dāng)前的增強(qiáng)是基于iBatisNet的,其數(shù)據(jù)庫(kù)操作都是基于單例模式實(shí)現(xiàn)的(借助了HttpContext),

所以我將數(shù)據(jù)庫(kù)連接及事務(wù)管理的相關(guān)方法,放在了‘增強(qiáng)繼承體系’中,

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

借用Service層,連接Dao層,實(shí)現(xiàn)真正的數(shù)據(jù)庫(kù)操作(包括 連接 和 事務(wù))。

具體的實(shí)現(xiàn)方式,就留給大家去探究了。

 

源碼(MVC4的項(xiàng)目 沒(méi)有packages文件夾):http://files.VEVb.com/files/08shiyan/AOPDemo.zip 

該源碼中,沒(méi)有針對(duì)當(dāng)前隨筆,做相應(yīng)的 demo. 

 

未完待續(xù)...

下篇隨筆,將實(shí)現(xiàn)簡(jiǎn)單的屬性注入 及 被代理對(duì)象延遲初始化。

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 绥德县| 南阳市| 图片| 登封市| 洪江市| 石门县| 孟连| 淮安市| 商水县| 北辰区| 庆城县| 宁明县| 常山县| 沙湾县| 徐闻县| 澎湖县| 广东省| 温泉县| 太和县| 临高县| 喜德县| 中宁县| 宁强县| 屯门区| 新晃| 兴海县| 彭山县| 黄冈市| 平邑县| 旌德县| 武功县| 东兰县| 洪泽县| 栖霞市| 额济纳旗| 阜城县| 营山县| 黔东| 固始县| 涡阳县| 明星|