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

posted @ 2020-10-08 13:24  豫若涉川  阅读(1632)  评论(0编辑  收藏  举报