190313-SpringCloud應用篇之AOP實現日誌功能
前面針對AOP的使用姿勢和一些疑問進行了說明,這一篇則從應用的角度出發,看下AOP可以實現些什麼樣的效果
I. AOP實現日誌攔截
1. 背景及目標
對於後端服務而言,一個日常的需求就是需要記錄一些關鍵方法呼叫歷史情況,用於分析介面的響應、問題定位排查等,屬於比較常見的場景了
因此,我們希望可以針對某些介面,知道傳入的引數時什麼,誰呼叫的,返回了啥,耗時多少這些基本資訊。顯然這些屬於公用的普適性需求,與方法本身的業務無關,如果直接在每個方法內部中加這個邏輯,就比較噁心了;為了最少的傾入性和通用性,正好可以使用AOP來實現這麼一個功能
- 攔截目標方法的執行
- 列印請求引數,返回結果和執行時間到日誌
2. 實現
這個屬於比較aop的簡單使用場景,因為需要知道返回結果,所有選擇 around
或者 afterReturning
advice;此外需要統計方法執行耗時,這樣就只能選中 around
了
首先我們支援自定義註解方式,先定義一個註解,只要這個方法上有這個註解,就攔截
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnoDot { }
其次,如果想更通用攔截指定包路徑下的方法,可以如下定義PointCut;注意下面語句中的 ||
表示或,只有有一個滿足即可
@Pointcut("execution(public * com.git.hui.boot.aop.demo.*.*(..)) || @annotation(AnoDot)") public void pointcut() { }
接著就是我們的advice實現了
@Around(value = "pointcut()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object res = null; String req = null; long start = System.currentTimeMillis(); try { req = buildReqLog(proceedingJoinPoint); res = proceedingJoinPoint.proceed(); return res; } catch (Throwable e) { res = "Un-Expect-Error"; throw e; } finally { long end = System.currentTimeMillis(); System.out.println(req + "" + JSON.toJSONString(res) + SPLIT_SYMBOL + (end - start)); } } private String buildReqLog(ProceedingJoinPoint joinPoint) { // 目標物件 Object target = joinPoint.getTarget(); // 執行的方法 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); // 請求引數 Object[] args = joinPoint.getArgs(); StringBuilder builder = new StringBuilder(target.getClass().getName()); builder.append(SPLIT_SYMBOL).append(method.getName()).append(SPLIT_SYMBOL); for (Object arg : args) { builder.append(JSON.toJSONString(arg)).append(","); } return builder.substring(0, builder.length() - 1) + SPLIT_SYMBOL; }
3. 測試
新增下測試程式碼,我們先建立兩個bean
// 這個bean下的方法,演示註解攔截 // com.git.hui.boot.aop.anodemo.AnoDemo @Component public class AnoDemo { @AnoDot public String gen(String ans) { return UUID.randomUUID() + "<>" + ans; } } // 這個bean下的方法,演示正則方式的攔截 // 注意前面的引數為..,表示任意引數型別和個數的方法都會攔截 // com.git.hui.boot.aop.demo.PrintDemo @Component public class PrintDemo { public String genRand(int seed, String suffix) { return seed + UUID.randomUUID().toString() + suffix; } }
啟動類如下
@SpringBootApplication public class Application { public Application(PrintDemo printDemo, AnoDemo anoDemo) { System.out.println(printDemo.genRand(10, "--一灰灰Blog")); System.out.println(anoDemo.gen("!23")); } public static void main(String[] args) { SpringApplication.run(Application.class); } }
輸出結果
com.git.hui.boot.aop.demo.PrintDemo|genRand|10,"--一灰灰Blog"|"10521195c0-3c2a-41d0-82f5-a41afad066b0--一灰灰Blog"|240 10521195c0-3c2a-41d0-82f5-a41afad066b0--一灰灰Blog com.git.hui.boot.aop.anodemo.AnoDemo|gen|"!23"|"1e3438fe-e31f-4f75-8405-4ff7494f9c9c<>!23"|26 1e3438fe-e31f-4f75-8405-4ff7494f9c9c<>!23
II. 其他
0. 專案
- 工程: spring-boot-demo
- 專案: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/011-aop-logaspect
1. 一灰灰Blog
- 一灰灰Blog個人部落格 https://blog.hhui.top
- 一灰灰Blog-Spring專題部落格 http://spring.hhui.top
一灰灰的個人部落格,記錄所有學習和工作中的博文,歡迎大家前去逛逛
2. 宣告
盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
- 微博地址:小灰灰Blog
- QQ: 一灰灰/3302797840
3. 掃描關注
一灰灰blog
知識星球
打賞 如果覺得我的文章對您有幫助,請隨意打賞。