java自定義注解,以編寫spring日志打印注解@ApiLog為例
1.聲明一個注解
基本元素 | 描述 |
---|---|
修飾符 | 訪問修飾符必須為public,不寫默認為pubic |
關鍵字 | 關鍵字為@interface |
注解名稱 | 注解名稱為自定義注解的名稱,使用時還會用到 |
注解類型元素 | 注解類型元素是注解中內容,可以理解成自定義接口的實現部分 |
例:
public @interface ApiLog {
}
2.@Target修飾注解
@Target用以表明該注解可以應用的java元素類型
類型 | 描述 |
---|---|
ElementType.TYPE | 應用於類、接口(包括注解類型)、枚舉 |
ElementType.FIELD | 應用於屬性(包括枚舉中的常量) |
ElementType.METHOD | 應用於方法 |
ElementType.PARAMETER | 應用於方法的形參 |
ElementType.CONSTRUCTOR | 應用於構造函數 |
ElementType.LOCAL_VARIABLE | 應用於局部變量 |
ElementType.ANNOTATION_TYPE | 應用於注解類型 |
ElementType.PACKAGE | 應用於包 |
ElementType.TYPE_PARAMETER | 1.8版本新增,應用於類型變量 |
ElementType.TYPE_USE | 1.8版本新增,應用於任何使用類型的語句中(例如聲明語句、泛型和強制轉換語句中的類型) |
例:
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ApiLog {
}
3.@Retention修飾注解
類型 | 描述 |
---|---|
RetentionPolicy.SOURCE | 編譯時被丟棄,不包含在類文件中 |
RetentionPolicy.CLASS | JVM加載時被丟棄,包含在類文件中,默認值 |
RetentionPolicy.RUNTIME | 由JVM 加載,包含在類文件中,在運行時可以被獲取到 |
例:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
}
4.@Document修飾注解
@Document表明該注解標記的元素可以被Javadoc 或類似的工具文檔化
例:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLog {
}
5.@Inherited修飾注解
表明使用了@Inherited注解的注解,所標記的類的子類也會擁有這個注解
例:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ApiLog {
}
6.編寫@ApiLog的實現切面類
例:
@Component
@Aspect
@Slf4j
public class MyApiLogAspect {
@Pointcut("@annotation(boss.xtrain.log.api.ApiLog) || @within(boss.xtrain.log.api.ApiLog)")
public void pointCut() {
// 切點
}
/**
* @description 打印請求報文和應答報文
* @params [joinPoint]
* @return java.lang.Object
*/
@Around("pointCut()")
public Object saveLog(ProceedingJoinPoint joinPoint) throws Throwable {
// 獲取當前時間
long reqTime = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currentTime = sdf.format(new Date(reqTime));
// 獲取請求ip
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = request.getRemoteAddr();
// 獲取調用方法和參數
String method = joinPoint.getSignature().getDeclaringType() + "." + joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
// 獲取全局流水號,全局流水號為本業務需要,若無請省略
Class<?> tmpClass = args[0].getClass();
Field field = tmpClass.getDeclaredField("globalMessageNo");
field.setAccessible(true);
Object gMessageNoObj = field.get(args[0]);
String gMessageNoStr = null;
if (null != gMessageNoObj) {
gMessageNoStr = (String) gMessageNoObj;
}
// 打印請求報文
log.info("請求報文:流水號:{} # 時間:{} # ip:{} # 調用方法:{} # 請求參數:>>>>>>>>>>{}", gMessageNoStr, currentTime, ip, method, args);
// 獲取應答結果
Object result = null;
result = joinPoint.proceed();
// 獲取處理時間
long respTime = System.currentTimeMillis() - reqTime;
// 打印應答報文
log.info("應答報文:流水號:{} # 時間:{} # 響應時間:{}ms # 返回參數:<<<<<<<<<<{}", gMessageNoStr, currentTime, respTime, result);
return result;
}
}
參考博客:https://blog.csdn.net/zt15732625878/article/details/100061528