前面的两篇随笔,都是只是个铺垫,真正实现增强四项基本功能的重头戏,在本篇随笔中,

本文将通过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(三) 实现增强四项基本功能相关推荐

  1. 从头认识Spring-3.4 简单的AOP日志实现-扩展添加检查订单功能,以便记录并检測输入的參数...

    这一章节我们再上一个章节的基础上加上一个检查订单功能 1.domain 蛋糕类: package com.raylee.my_new_spring.my_new_spring.ch03.topic_1 ...

  2. 简单理解TCP三次握手四次挥手(看一遍你就懂)

    什么是TCP协议? TCP( Transmission control protocol )即传输控制协议,是一种面向连接.可靠的数据传输协议,它是为了在不可靠的互联网上提供可靠的端到端字节流而专门设 ...

  3. java after方法_spring AOP的After增强实现方法实例分析

    本文实例讲述了spring AOP的After增强实现方法.分享给大家供大家参考,具体如下: 一 配置 xmlns:xsi="http://www.w3.org/2001/XMLSchema ...

  4. Flash Builder4.7极其简单破解方法-三步搞定(亲测)

    资讯类型: 转载 来源页面: http://weibo.com/2101024913/yvmR0D9Df 资讯原标题: 资讯原作者: 丿卓越丶星辰 翻译词数: 词 我的评论: 对这篇文你有啥看法,跟贴 ...

  5. 分布式锁简单入门以及三种实现方式介绍(滴滴)

    很多小伙伴在学习Java的时候,总是感觉Java多线程在实际的业务中很少使用,以至于不会花太多的时间去学习,技术债不断累积!等到了一定程度的时候对于与Java多线程相关的东西就很难理解,今天需要探讨的 ...

  6. Group Box组合框的简单使用 [大三TJB_708]

    http://blog.csdn.net/misskissc/article/details/9317783 Group Box组合框的简单使用 [大三TJB_708] 转载于:https://www ...

  7. 手动实现一个迷你版的AOP(实战增强版)

    在正式进行aop模块的介绍之前,我们需要先弄懂一些基本的术语概念. 在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期间动 ...

  8. 【OGG】OGG简单配置双向复制(三)

    [OGG]OGG简单配置双向复制(三) 一.1 BLOG文档结构图 一.2 前言部分 一.2.1 导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_ ...

  9. Flash Builder4.7极其简单破解方法-三步搞定

    Flash Builder4.7极其简单破解方法-三步搞定(亲测) 原方法适用于4.6版本,同样方法4.7完美破解,不敢独享 具体步骤如下: 1.到Adobe官网下载FlashBuilder 4.6, ...

最新文章

  1. 皮一皮:碰到这样的领导怎么办...
  2. 035_Unicode对照表一
  3. SVN服务器与客户端的配置
  4. LDAP 查询基本知识
  5. css 让div 的高度和屏幕的高度一样
  6. Html5开发之链接标签nav的用法
  7. python小明爬楼梯_爬楼梯(Python and C++解法)
  8. 解决在eclipse里没有“Dynamic Web Project“这个选项的问题
  9. 第九周-每周例行报告
  10. 《剑指offer》66道算法题合集(java实现)
  11. ESP32 学习笔记(二十一)电源管理
  12. vnr光学识别怎么打开_物流仓库安防监控系统安装的作用和功能
  13. 基于FPGA的AD9854并行接口驱动(VerilogHDL语言)
  14. 个人怎么做微信小程序?
  15. 服务器系统壁纸,云服务器壁纸
  16. 12步解N-S方程之第二步
  17. html输入浮点型,对于input框限定输入值为浮点型的js代码
  18. 习题9-4 查找书籍 (20分)PTA给定n本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。
  19. 面试心得与总结:BAT、网易、蘑菇街
  20. 年会直播方案应该怎么做

热门文章

  1. nslang oracle_解决ojdbc14连接oracle报“java.sql.SQLException: Io 异常: Size Data Unit (SDU) mismatch”异常问题...
  2. python统计学书籍推荐_一位90后统计学硕士的深悟:统计其实有门道!AI还能这样学!(精荐40本书+20视频资源...
  3. 故障码123401_电力系统规划设计对电力工程设计的应用
  4. monkey测试_安卓测试之monkey
  5. 学计算机需要带笔记本电脑,一年级学生必须带电脑上学吗?顾问给出建议,父母需要事先了解...
  6. phpstorm安装_快速打造自己的PHPStorm主题
  7. python如何测试仪器_使用python检测一个设备是否ping的通
  8. php 剪贴板,之Windows中的剪贴板
  9. Java追加写json_java – ObjectMapper追加文件JSON
  10. createbitmap 旋转90度_小学数学,图形的运动,平移与旋转