java自定义注解,以编写spring日志打印注解@ApiLog为例
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