Spring Boot 學習之路——4 AOP註解方式實現列印日誌
阿新 • • 發佈:2018-12-29
前言:
據XX統計,四分之一的程式碼都是日誌有關,日誌對於定位和解決問題尤為重要,以前公司的編碼規範中要求介面必須在日誌中記錄入參和返回值以及關鍵程式碼,引數部分完全可以用Spring的AOP——面向切面來實現。
什麼叫AOP?
百度:AOP(Aspect Oriented Programming),意為:面向切面程式設計,通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數語言程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
AspectJ是AOP的一個很悠久的實現,它能夠和 Java 配合起來使用。
簡單介紹完概念,上程式碼。
1.定義日誌註解類
package com.joanna.annotationdemo.demo.annotation; import java.lang.annotation.*; /** * 監聽每個方法傳入的引數、返回值,列印日誌 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface LoggerProfile { // 方法註釋 String methodNote(); }
2.定義日誌處理的切面類
package com.joanna.annotationdemo.demo.annotation; importcom.alibaba.fastjson.JSON; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * 使用AOP對方法進行日誌記錄 */ @Aspect//表示這是一個切面類 @Component//加入IOC容器 public class LoggerProfilerIntercepter { private static final Logger LOGGER = LoggerFactory.getLogger("LoggerProfilerDemo"); // 用@PointCut註解統一宣告,然後在其它通知中引用該統一宣告即可! @Pointcut("@annotation(com.joanna.annotationdemo.demo.annotation.LoggerProfile)") public void loggerProfilePointCut() { } // 環繞通知@Around 修飾的方法一定要將方法的返回值返回!本身相當於代理! @Around("loggerProfilePointCut()") public Object doLoggerProfiler(final ProceedingJoinPoint joinPoint) throws Throwable { Map<String, Object> logMap = new HashMap<String, Object>(); // part 1 獲取目標方法名、引數等 try { if (LOGGER.isInfoEnabled()) { String className = joinPoint.getTarget().getClass().getName(); logMap.put("className", className); String methodName = joinPoint.getSignature().getName(); logMap.put("methodName", methodName); Method method = getMethod(joinPoint); LoggerProfile loggerProfile = method.getAnnotation(LoggerProfile.class); String methodNote = loggerProfile.methodNote(); if (null != methodNote && methodNote.length() > 0) { logMap.put("note", methodNote); } Object[] args = joinPoint.getArgs(); if (null != args && args.length > 0) { for (int i = 0; i < args.length; i++) { logMap.put("arg-" + i, args[i]); } } } } catch (Exception e) { LOGGER.error("LoggerProfile Part 1 Exception ", e); } // part 2 執行目標方法 Object obj = null; Exception error = null; try { obj = joinPoint.proceed(); } catch (Exception e) { error = e; } // part 3 獲取返回值 try { if (LOGGER.isInfoEnabled()) { if (null != error) { logMap.put("error", error); } else { if (null != obj) { logMap.put("result", obj); } } LOGGER.info(JSON.toJSONString(logMap)); } } catch (Exception e) { LOGGER.error("LoggerProfile Part 2 Exception ", e); } return obj; } /** * 獲取當前方法 * * @param joinPoint * @return * @throws NoSuchMethodException */ private Method getMethod(final JoinPoint joinPoint) throws NoSuchMethodException { final Signature sig = joinPoint.getSignature(); if (!(sig instanceof MethodSignature)) { throw new NoSuchMethodException( "This annotation is only valid on a method."); } final MethodSignature msig = (MethodSignature) sig; final Object target = joinPoint.getTarget(); return target.getClass().getMethod(msig.getName(), msig.getParameterTypes()); } }
3.新增依賴:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.8</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.8</version> </dependency>
4.在controller方法上添加註解
@LoggerProfile(methodNote = "humanSays") @RequestMapping(value = "/humanSays", method = RequestMethod.GET) public String humanSays(@RequestParam(name = "name", required = false) String name, @RequestParam(name = "comeFrom", required = false) String comeFrom) { return "Hello " + name + ", who comes from " + comeFrom + ", I'm a human , hahaha"; }
5.測試
啟動專案,訪問:http://localhost:8080/sayHello/humanSays?name=Joanna&comeFrom=China
可以看到console中列印: