AOP(Aspect-Oriented Programming,面向切面的编程),它是能够经过预编译方式和运行期动态代理实如今不修改源代码的状况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。OOP是关注将需求功能划分为不一样的而且相对独立,封装良好的类,并让它们有着属于本身的行为,依靠继承和多态等来定义彼此的关系;AOP是但愿可以将通用需求功能从不相关的类当中分离出来,可以使得不少类共享一个行为,一旦发生变化,没必要修改不少类,而只须要修改这个行为便可。AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是经过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。可是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,好比日志记录,权限验证,异常拦截等。html
博主以为它的优点主要表如今:编程
一、将通用功能从业务逻辑中抽离出来,能够省略大量重复代码,有利于代码的操做和维护。架构
二、在软件设计时,抽出通用功能(切面),有利于软件设计的模块化,下降软件架构的复杂度。也就是说通用的功能都是一个单独的模块,在项目的主业务里面是看不到这些通用功能的设计代码的。框架
为了说明AOP的工做原理,博主打算先从一个简单的例子开始,经过静态拦截的方式来了解AOP是如何工做的。ide
public class Order { public int Id { set; get; } public string Name { set; get; } public int Count { set; get; } public double Price { set; get; } public string Desc { set; get; } } public interface IOrderProcessor { void Submit(Order order); } public class OrderProcessor : IOrderProcessor { public void Submit(Order order) { Console.WriteLine("提交订单"); } } public class OrderProcessorDecorator : IOrderProcessor { public IOrderProcessor OrderProcessor { get; set; } public OrderProcessorDecorator(IOrderProcessor orderprocessor) { OrderProcessor = orderprocessor; } public void Submit(Order order) { PreProceed(order); OrderProcessor.Submit(order); PostProceed(order); } public void PreProceed(Order order) { Console.WriteLine("提交订单前,进行订单数据校验...."); if (order.Price < 0) { Console.WriteLine("订单总价有误,请从新核对订单。"); } } public void PostProceed(Order order) { Console.WriteLine("提交带单后,进行订单日志记录......"); Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "提交订单,订单名称:" + order.Name + ",订单价格:" + order.Price); } }
调用代码:模块化
static void Main(string[] args) { Order order = new Order() { Id = 1, Name = "lee", Count = 10, Price = 100.00, Desc = "订单测试" }; IOrderProcessor orderprocessor = new OrderProcessorDecorator(new OrderProcessor()); orderprocessor.Submit(order); Console.ReadLine(); }
获得结果:post
上面咱们模拟订单提交的例子,在提交一个订单前,咱们须要作不少的准备工做,好比数据有效性校验等;订单提交完成以后,咱们还须要作日志记录等。上面的代码很简单,没有任何复杂的逻辑,从上面的代码能够看出,咱们经过静态植入的方式手动在执行方法前和执行方法后让它作一些咱们须要的功能。AOP的实现原理应该也是如此,只不过它帮助咱们作了方法拦截,帮咱们省去了大量重复代码,咱们要作的仅仅是写好拦截前和拦截后须要处理的逻辑。测试
了解了静态拦截的例子,你是否对AOP有一个初步的认识了呢。下面咱们就来到底AOP该如何使用。按照园子里面不少牛人的说法,AOP的实现方式大体能够分为两类:动态代理和IL 编织两种方式。博主也不打算照本宣科,分别拿Demo来讲话吧。下面就以两种方式各选一个表明框架来讲明。this
动态代理方式,博主就以微软企业库(MS Enterprise Library)里面的PIAB(Policy Injection Application Block)框架来做说明。spa
首先须要下载如下几个dll,而后添加它们的引用。
而后定义对应的Handler
public class User { public string Name { set; get; } public string PassWord { set; get; } } #region 一、定义特性方便使用 public class LogHandlerAttribute : HandlerAttribute { public string LogInfo { set; get; } public int Order { get; set; } public override ICallHandler CreateHandler(IUnityContainer container) { return new LogHandler() { Order = this.Order, LogInfo = this.LogInfo }; } } #endregion #region 二、注册对须要的Handler拦截请求 public class LogHandler : ICallHandler { public int Order { get; set; } public string LogInfo { set; get; } //这个方法就是拦截的方法,能够规定在执行方法以前和以后的拦截 public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { Console.WriteLine("LogInfo内容" + LogInfo); //0.解析参数 var arrInputs = input.Inputs; if (arrInputs.Count > 0) { var oUserTest1 = arrInputs[0] as User; } //1.执行方法以前的拦截 Console.WriteLine("方法执行前拦截到了"); //2.执行方法 var messagereturn = getNext()(input, getNext); //3.执行方法以后的拦截 Console.WriteLine("方法执行后拦截到了"); return messagereturn; } } #endregion #region 三、用户定义接口和实现 public interface IUserOperation { void Test(User oUser); void Test2(User oUser, User oUser2); } //这里必需要继承这个类MarshalByRefObject,不然报错 public class UserOperation : MarshalByRefObject, IUserOperation { private static UserOperation oUserOpertion = null; public UserOperation() { //oUserOpertion = PolicyInjection.Create<UserOperation>(); } //定义单例模式将PolicyInjection.Create<UserOperation>()产生的这个对象传出去,这样就避免了在调用处写这些东西 public static UserOperation GetInstance() { if (oUserOpertion == null) oUserOpertion = PolicyInjection.Create<UserOperation>(); return oUserOpertion; } //调用属性也会拦截 public string Name { set; get; } //[LogHandler],在方法上面加这个特性,只对此方法拦截 [LogHandler(LogInfo = "Test的日志为aaaaa")] public void Test(User oUser) { Console.WriteLine("Test方法执行了"); } [LogHandler(LogInfo = "Test2的日志为bbbbb")] public void Test2(User oUser, User oUser2) { Console.WriteLine("Test2方法执行了"); } } #endregion
最后咱们来看调用的代码:
static void Main(string[] args) { try { var oUserTest1 = new User() { Name = "test2222", PassWord = "yxj" }; var oUserTest2 = new User() { Name = "test3333", PassWord = "yxj" }; var oUser = UserOperation.GetInstance(); oUser.Test(oUserTest1); oUser.Test2(oUserTest1,oUserTest2); } catch (Exception ex) { //throw; } }
获得结果以下:
咱们来看执行Test()方法和Test2()方法时候的顺序。
因为Test()和Test2()方法上面加了LogHander特性,这个特性里面定义了AOP的Handler,在执行Test和Test2方法以前和以后都会进入Invoke()方法里面。其实这就是AOP的意义所在,将切面的通用功能在统一的地方处理,在主要逻辑里面直接用过特性使用便可。
静态织入的方式博主打算使用PostSharp来讲明,一来这个使用起来简单,二来项目中用过这种方式。
Postsharp从2.0版本就开始收费了。为了说明AOP的功能,博主下载了一个免费版本的安装包,使用PostSharp与其它框架不太同样的是必定要下载安装包安装,只引用类库是不行的,由于上文说过,AOP框架须要为编译器或运行时添加扩展。使用步骤以下:
(1)下载Postsharp安装包,安装。
(2)在须要使用AOP的项目中添加PostSharp.dll 这个dll的引用。
(3)定义拦截的方法:
[Serializable] public class TestAop : PostSharp.Aspects.OnMethodBoundaryAspect {
//发生异常时进入此方法 public override void OnException(MethodExecutionArgs args) { base.OnException(args); }
//执行方法前执行此方法 public override void OnEntry(MethodExecutionArgs args) { base.OnEntry(args); }
//执行方法后执行此方法 public override void OnExit(MethodExecutionArgs args) { base.OnExit(args); } }
注意这里的TestAop这个类必需要是可序列化的,因此要加上[Serializable]特性
(4)在须要拦截功能的地方使用。
在类上面加特性拦截,此类下面的全部的方法都会具备拦截功能。
[TestAop]public class Impc_TM_PLANT : Ifc_TM_PLANT { /// <summary> /// 获取或设置服务接口。 /// </summary> private Ic_TM_PLANTService service { get; set; } public IList<DTO_TM_PLANT> Find() { DTO_TM_PLANT otest = null; otest.NAME_C = "test";//异常,会进入OnException方法
return service.FindAll();
}
}
方法上面加特性拦截,只会拦截此方法。
[TestAop] public IList<DTO_TM_PLANT> Find() { DTO_TM_PLANT otest = null; otest.NAME_C = "test"; return service.FindAll(); }
有没有感受很简单,很强大,其实这一简单应用,解决咱们常见的日志、异常、权限验证等功能简直过小菜一碟了。固然Postsharp可能还有许多更加高级的功能,有兴趣能够深究下。
public class AOPFilterAttribute : ActionFilterAttribute, IExceptionFilter { public void OnException(ExceptionContext filterContext) { throw new System.NotImplementedException(); } public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } }
在controller里面使用该特性:
[AOPFilter] public JsonResult GetEditModel(string strType) { var lstRes = new List<List<DragElementProp>>(); var lstResPage = new List<PageProperty>();
//.........todo return Json(new { lstDataAttr = lstRes, PageAttr = lstResPage, lstJsConnections = lstJsPlumbLines }, JsonRequestBehavior.AllowGet); }
调试可知,在执行GetEditModel(string strType)方法以前,会先执行OnActionExecuting()方法,GetEditModel(string strType)以后,又会执行OnActionExecuted()方法。这在咱们MVC里面权限验证、错误页导向、日志记录等经常使用功能均可以方便解决。