背景
無論是對外提供的RPC接口,還是項目內的普通方法,我們都會有需要打印方法入參、出參的需求,方便在遇到問題時通過查看日誌快速定位,我們也會需要對方法的執行時間進行打印 方便分析和調優。
比較笨的做法就是在每個需要打印日誌的地方使用log.info對參數進行打印,在每個方法內部方法體前後獲取系統時間 在最後打印時間差
但這種對方法自身業務邏輯沒有什麼意義的的代碼 侵入性太強 編寫時也浪費時間 所以我們可以通過註解+AOP的方法 對這些操作進行封裝 基於註解的控制又方便隨時隨地的使用
怎麼做
定義註解
package com.common.interceptor.annotation;
import java.lang.annotation.*;
/**
* 方法執行的入參 出參 及 執行時間
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RunTimeAnnotation {
}
Aspect
我們使用Aspect進行切面開發
首先引用對應的pom依賴
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.3</version>
</dependency>
定義切面類:
這裏使用@Around定義環繞通知
package com.common.interceptor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class RunTimeAspect {
private static final Logger logger = LoggerFactory.getLogger(RunTimeAspect.class);
@Around("@annotation(com.common.interceptor.annotation.RunTimeAnnotation)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
long startTime = System.currentTimeMillis();
//接收到請求,記錄請求內容
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//獲取參數
Object[] args = joinPoint.getArgs();
//獲取方法
String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
Object obj = null;
try {
logger.info("{}方法執開始執行,入參{}",methodName,args);
obj = joinPoint.proceed();
long excuteTime = System.currentTimeMillis() - startTime;
logger.info("{}方法執結束執行,耗時{}ms,入參{},返回值{}",methodName,excuteTime,args,obj);
} catch (Exception throwable) {
logger.error("{}方法執行異常{}",methodName,throwable);
//異常要拋出去 否則會影響外部方法事務回滾
throw throwable;
}
return obj;
}
}
寫好後,我們只需要在需要的地方加上@RunTimeAnnotation 註解就可以了
@RunTimeAnnotation
public void consumer(String message){
//...
}