一大早,小王就急匆匆的跑過來找我,說:周哥,那個記錄日誌的功能我想請教一下。java
由於公司某個項目要跟別的平臺作對接,咱們這邊須要給他們提供一套接口。昨天,我就將記錄接口日誌的工做安排給了小王。web
下面是我跟小王的主要對話。app
我:說說怎麼了?ide
小王:我將記錄接口日誌的功能放到了每一個controller中,如今感受有點繁瑣,我這樣作是否是不太合適?post
我:爲何要去每一個接口裏記錄日誌?優化
小王:最開始我是用的攔截器,可是這樣一個請求就記錄了兩條記錄。加密
我:爲何是兩條?日誌
小王:在preHandle中記錄一條請求數據,在postHandle中記錄一條響應數據。code
我:。。。你不是說你會Aop嗎?對象
小王:Aop也是同樣,在前置通知記錄一條請求數據,後置通知記錄一條響應數據。
小王:這個數據和之前記錄操做日誌的不太同樣,之前只須要在前置通知記錄一條操做日誌就能夠了,可是如今有響應,因此只能在controller中記錄日誌了。
我:那你知不知道有個環繞通知?你說一下Aop就幾種通知類型。
小王:總共有五種,分別是:
接下來,咱們一塊兒來演示一下如何使用環繞通知來解決小王的問題。
第一步:提供接口用來接收參數和響應接口
@RestController public class TestController { @GetMapping("/getName") public String getName(HttpServletRequest request) throw Exception { String result = "Java旅途"; String age = request.getParameter("age"); if("18".equals(age)){ result = "沒法識別"; } return result; } }
第二步:定義切點
execution()是比較經常使用的定義切點的表達式,execution()語法以下:
execution(修飾符 返回值 包.類.方法名(參數) throws異常)
其中:
修飾符和throws異常能夠省略不寫
根據這些解釋,咱們能夠將第一步中的接口用execution()表達式來描述一下:
execution(String binzh.website.controller.TestController.GetName(HttpServletRequest))
*
:匹配全部項
..
:匹配任意個方法參數..
出如今類名中時,後面必須跟*
,表示包、子孫包下的全部類;如今咱們優化一下上面的表達式,定義切面爲controller包及controller下面全部包的全部方法
execution(* binzh.website.controller..*.*(..))
第三步:環繞通知記錄日誌
@Around("execution(* binzh.website.controller..*.*(..))") public Object around(ProceedingJoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String age = request.getParameter("age"); Object proceed = ""; try { proceed = joinPoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("age==="+age); System.out.println("proceed ===="+proceed); return proceed; }
運行結果以下:
age===19 proceed ====Java旅途
咱們之因此能夠用環繞通知來處理小王的問題。其中一個重要的緣由就是,咱們提供的全部接口都是通過統一加密的,最後請求的參數都是一個固定的名字。還須要注意的一點就是,環繞通知的返回值類型必須大於等於方法的返回值,即:加入你方法返回String類型,環繞通知不能寫成void類型。
小王看到這裏後,恍然大悟,準備趕忙回去試一下。我急忙拉住他。
我:若是接口出現異常了怎麼辦?
小王:那我在異常通知裏處理就能夠了。
我:你再想一下?
小王:好像不行,異常通知裏獲取不到請求參數。
我:在環繞通知中捕獲處理能夠嗎?
這時候,看見小王眼睛發光,驚訝的說了一句:環繞通知太牛批了,居然能夠完成前置通知、後置通知和異常通知的工做!
這篇文章戲有點多,別見怪。實戰是提高技術最有效的途徑!