AOP面向切面编程简介

来源:互联网 发布:西英格兰大学 知乎 编辑:程序博客网 时间:2024/06/06 19:15
 AOP这个词相信大家都没有接触太多过,但是实际上你们已经有所接触了,就在设计模式中。AOP所用的思想其实和设计模式是一样的,即在不修改原代码的情况下统一增加或者修改功能。还有,AOP大多用在spring里面,但是本文所写的只是在MVC中的应用,要注意。


一、简介


        所谓AOP(Aspect Oriented Programming的缩写)意为

切面的编通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

        以上是百度百科的官方解释,但是在我看来,其实AOP更多的是一种思想,一种可以动一发而通全身的思想,AOP其实面对的更多是一种同意的功能或者调用过程来进行编写的一种程序体,从它的第一个词Aspect(切面)也就是指的一个方面,也可以了解到这种方式也就是针对一个方面的实现,这一点其实和mvc中的global文件很像,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

        其次就是它的预编译性质可以很好的处理一些错误或者是预先判断一些情况,这也导致了它在设计的时候在判断权限,统一输出某个东西方面变得比较常见。“可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。”上面这句话也是对于AOP的很好的诠释。


二、在MVC中的实现


        说了这么多了,让我们来实战一下吧,首先我们需要在vs新建一个mvc的项目,选择MVC3或者是4都OK,然后建立一个controller,命名随意,然后建立他的视图,在视图上写上最简单的HelloWorld。


[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <!DOCTYPE html>  
  2.   
  3. <html>  
  4. <head>  
  5.     <title>Index</title>  
  6. </head>  
  7. <body>  
  8.     <div>  
  9.         <a>Hello! World</a>  
  10.     </div>  
  11. </body>  
  12. </html>  


        右图是我创建好的MVC解决方案和添加好的controller还有view,在view中写入上面的代码以显示Hello!World。

         运行之后(不会运行的自行百度)是不是就显示出了一个HelloWorld的字样在网页上呢?

         好,接下来我们开始新建AOP的一个文件然后去使用,首先在本项目中新添加一个类,名字叫FilterPublic,在引用的地方添加using  System.Web.Mvc这个引用,然后让这个类继承于ActionFilterAttribute,大家要注意Action这个词,说明这个东西是基于动作的。

        然后我们写入以下代码:


[csharp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public string Message { getset; }  
  2.   
  3. public override void OnActionExecuting(ActionExecutingContext filterContext)  
  4. {  
  5.     base.OnActionExecuting(filterContext);  
  6.     filterContext.HttpContext.Response.Write("Action执行之前" + Message + "<br />");  
  7. }  
  8.   
  9. public override void OnActionExecuted(ActionExecutedContext filterContext)  
  10. {  
  11.     base.OnActionExecuted(filterContext);  
  12.     filterContext.HttpContext.Response.Write("Action执行之后" + Message + "<br />");  
  13. }  
  14.   
  15. public override void OnResultExecuting(ResultExecutingContext filterContext)  
  16. {  
  17.     base.OnResultExecuting(filterContext);  
  18.     filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />");  
  19. }  
  20.   
  21. public override void OnResultExecuted(ResultExecutedContext filterContext)  
  22. {  
  23.     base.OnResultExecuted(filterContext);  
  24.     filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />");  
  25. }  

        这个里面就是Filter触发的各种动作,然后我们在controller里面的默认方法做以下修改:


[csharp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. [<span style="font-size:18px;">FilterPublic</span>(Message = "Action")]  
  2. public ActionResult Index()  
  3. {  
  4.     HttpContext.Response.Write("Action正在执行···<br />");  
  5.     return Content("正在返回Result···<br />");  
  6. }  

然后在controller的class类上面也添加一句[FilterPublic(Message = "Controller")],然后运行,会出现什么结果呢?

[plain] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. Action执行之前Action  
  2. Action正在执行···  
  3. Action执行之后Action  
  4. 返回Result之前Action  
  5. 正在返回Result···  
  6. 返回Result之后Action  


        可以看到controller里面的方法在执行之前会去先执行以下我们设置的FilterPublic里面的代码,而且随着里面动作发生时间不同也可以看出了都是哪个方法被触发了。

        但是在controller上面写的基于controller的方法却没有触发,这是为什么呢?

         其实这个问题很简单,就是我们在设置我们的AOP程序的时候没有进行参数的设置,没有让filter进行叠加的运行,这个时候我们只要在写的FilterPublic类的上面加上:[AttributeUsage(AttributeTargets.All, AllowMultiple = true)],就可以让你设置的各种filter或者叠加的filter进行触发了,这个时候我们再运行一下试试:


[plain] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. Action执行之前Controller  
  2. Action执行之前Action  
  3. Action正在执行···  
  4. Action执行之后Action  
  5. Action执行之后Controller  
  6.   
  7. 返回Result之前Controller  
  8. 返回Result之前Action  
  9. 正在返回Result···  
  10. 返回Result之后Action  
  11. 返回Result之后Controller  

       这样一来,在controller上的Filter也被触发了,所以我们使用AOP的方法只需要在我们自己的写的方法或者页面默认的加载方法上面写上一个filter类的标签就可以了。

       那么,如果我们有个功能需要所有的页面都触发,这样岂不是也很麻烦么?别担心,这个时候就轮到我们的global文件发挥作用了。在global.asax文件下面的RegisterGlobalFilters方法下面注册自己写的Filter就可以了:


[csharp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public static void RegisterGlobalFilters(GlobalFilterCollection filters)  
  2. {  
  3.     filters.Add(new HandleErrorAttribute());  
  4.     //把自己的filter定义成全局的filter  
  5.     filters.Add(new <span style="font-size:18px;">FilterPublic</span>() { Message = "全局<br/>" });  
  6.   
  7. }  

然后运行,看结果:


[plain] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. Action执行之前全局  
  2.   
  3. Action执行之前Controller  
  4. Action执行之前Action  
  5. Action正在执行···  
  6. Action执行之后Action  
  7. Action执行之后Controller  
  8. Action执行之后全局  
  9.   
  10. 返回Result之前全局  
  11.   
  12. 返回Result之前Controller  
  13. 返回Result之前Action  
  14. 正在返回Result···  
  15. 返回Result之后Action  
  16. 返回Result之后Controller  
  17. 返回Result之后全局  

这样全局的触发也就做好了(filter中的message只是用于标识层级的,正式用的时候可以不用定义。)


        这样一看,如果想要快速的添加一个全局都用的方法,只需要新建一个Filter,然后再改一下global文件就可以办到了,是不是很方便呢。


    以上均为本人对于AOP的一些浅浅的研究,如有错误的地方还请读者指正。

0 0
原创粉丝点击