MVC AOP面向切面編程
AOP這個(gè)詞相信大家都沒有接觸太多過,但是實(shí)際上你們已經(jīng)有所接觸了,就在設(shè)計(jì)模式中。AOP所用的思想其實(shí)和設(shè)計(jì)模式是一樣的,即在不修改原代碼的情況下統(tǒng)一增加或者修改功能。還有,AOP大多用在spring里面,但是本文所寫的只是在MVC中的應(yīng)用,要注意。

一、簡介
        所謂AOP(Aspect Oriented Programming的縮寫)意為面向切面的編程,通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。
        以上是百度百科的官方解釋,但是在我看來,其實(shí)AOP更多的是一種思想,一種可以動一發(fā)而通全身的思想,AOP其實(shí)面對的更多是一種同意的功能或者調(diào)用過程來進(jìn)行編寫的一種程序體,從它的第一個(gè)詞Aspect(切面)也就是指的一個(gè)方面,也可以了解到這種方式也就是針對一個(gè)方面的實(shí)現(xiàn),這一點(diǎn)其實(shí)和mvc中的global文件很像,也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。
其次就是它的預(yù)編譯性質(zhì)可以很好的處理一些錯(cuò)誤或者是預(yù)先判斷一些情況,這也導(dǎo)致了它在設(shè)計(jì)的時(shí)候在判斷權(quán)限,統(tǒng)一輸出某個(gè)東西方面變得比較常見。“可以通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動態(tài)統(tǒng)一添加功能的一種技術(shù)。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,提高代碼的靈活性和可擴(kuò)展性,AOP可以說也是這種目標(biāo)的一種實(shí)現(xiàn)。”上面這句話也是對于AOP的很好的詮釋。
二、在MVC中的實(shí)現(xiàn)
說了這么多了,讓我們來實(shí)戰(zhàn)一下吧,首先我們需要在vs新建一個(gè)mvc的項(xiàng)目,選擇MVC3或者是4都OK,然后建立一個(gè)controller,命名隨意,然后建立他的視圖,在視圖上寫上最簡單的HelloWorld。
<!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> <a>Hello! World</a> </div> </body> </html>
        右圖是我創(chuàng)建好的MVC解決方案和添加好的controller還有view,在view中寫入上面的代碼以顯示Hello!World。

         運(yùn)行之后(不會運(yùn)行的自行百度)是不是就顯示出了一個(gè)HelloWorld的字樣在網(wǎng)頁上呢?
         好,接下來我們開始新建AOP的一個(gè)文件然后去使用,首先在本項(xiàng)目中新添加一個(gè)類,名字叫FilterPublic,在引用的地方添加using  System.Web.Mvc這個(gè)引用,然后讓這個(gè)類繼承于ActionFilterAttribute,大家要注意Action這個(gè)詞,說明這個(gè)東西是基于動作的。
然后我們寫入以下代碼:
public string Message { get; set; }  public override void OnActionExecuting(ActionExecutingContext filterContext) {   base.OnActionExecuting(filterContext);   filterContext.HttpContext.Response.Write("Action執(zhí)行之前" + Message + "<br />"); }  public override void OnActionExecuted(ActionExecutedContext filterContext) {   base.OnActionExecuted(filterContext);   filterContext.HttpContext.Response.Write("Action執(zhí)行之后" + Message + "<br />"); }  public override void OnResultExecuting(ResultExecutingContext filterContext) {   base.OnResultExecuting(filterContext);   filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />"); }  public override void OnResultExecuted(ResultExecutedContext filterContext) {   base.OnResultExecuted(filterContext);   filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />"); } 這個(gè)里面就是Filter觸發(fā)的各種動作,然后我們在controller里面的默認(rèn)方法做以下修改:
[<span style="font-size:18px;">FilterPublic</span>(Message = "Action")] public ActionResult Index() {   HttpContext.Response.Write("Action正在執(zhí)行???<br />");   return Content("正在返回Result???<br />"); } 然后在controller的class類上面也添加一句[FilterPublic(Message = "Controller")],然后運(yùn)行,會出現(xiàn)什么結(jié)果呢?
Action執(zhí)行之前Action Action正在執(zhí)行??? Action執(zhí)行之后Action 返回Result之前Action 正在返回Result??? 返回Result之后Action
可以看到controller里面的方法在執(zhí)行之前會去先執(zhí)行以下我們設(shè)置的FilterPublic里面的代碼,而且隨著里面動作發(fā)生時(shí)間不同也可以看出了都是哪個(gè)方法被觸發(fā)了。
       但是在controller上面寫的基于controller的方法卻沒有觸發(fā),這是為什么呢?
其實(shí)這個(gè)問題很簡單,就是我們在設(shè)置我們的AOP程序的時(shí)候沒有進(jìn)行參數(shù)的設(shè)置,沒有讓filter進(jìn)行疊加的運(yùn)行,這個(gè)時(shí)候我們只要在寫的FilterPublic類的上面加上:[AttributeUsage(AttributeTargets.All, AllowMultiple = true)],就可以讓你設(shè)置的各種filter或者疊加的filter進(jìn)行觸發(fā)了,這個(gè)時(shí)候我們再運(yùn)行一下試試:
Action執(zhí)行之前Controller Action執(zhí)行之前Action Action正在執(zhí)行??? Action執(zhí)行之后Action Action執(zhí)行之后Controller 返回Result之前Controller 返回Result之前Action 正在返回Result??? 返回Result之后Action 返回Result之后Controller
       這樣一來,在controller上的Filter也被觸發(fā)了,所以我們使用AOP的方法只需要在我們自己的寫的方法或者頁面默認(rèn)的加載方法上面寫上一個(gè)filter類的標(biāo)簽就可以了。
那么,如果我們有個(gè)功能需要所有的頁面都觸發(fā),這樣豈不是也很麻煩么?別擔(dān)心,這個(gè)時(shí)候就輪到我們的global文件發(fā)揮作用了。在global.asax文件下面的RegisterGlobalFilters方法下面注冊自己寫的Filter就可以了:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {   filters.Add(new HandleErrorAttribute());   //把自己的filter定義成全局的filter   filters.Add(new <span style="font-size:18px;">FilterPublic</span>() { Message = "全局<br/>" });  } 然后運(yùn)行,看結(jié)果:
Action執(zhí)行之前全局 Action執(zhí)行之前Controller Action執(zhí)行之前Action Action正在執(zhí)行??? Action執(zhí)行之后Action Action執(zhí)行之后Controller Action執(zhí)行之后全局 返回Result之前全局 返回Result之前Controller 返回Result之前Action 正在返回Result??? 返回Result之后Action 返回Result之后Controller 返回Result之后全局
這樣全局的觸發(fā)也就做好了(filter中的message只是用于標(biāo)識層級的,正式用的時(shí)候可以不用定義。)
這樣一看,如果想要快速的添加一個(gè)全局都用的方法,只需要新建一個(gè)Filter,然后再改一下global文件就可以辦到了,是不是很方便呢。
以上均為本人對于AOP的一些淺淺的研究,如有錯(cuò)誤的地方還請讀者指正。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
新聞熱點(diǎn)
疑難解答
圖片精選