通过自定义注解实现日志拦截

背景

在我们的开发过程中,日志使用的很普遍,并且使用也非常方便,因为它将很多的细节都进行了封装,我们只需@+使用即可。那么如果我们需要实现一个自定义注解可以怎么做呢;接下来,我将带大家一步一步了解自定义注解的实现过程。

 

实现过程

这里我将以记录一个web系统的请求日志功能,介绍通过自定义注解实现的全过程,提前我们创建好一个Springboot项目

引入对应依赖包(修改pom文件)

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

然后我们先定义一个注解接口类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
    /** 模块 **/
    String title() default "";

    /**  动作 **/
    String action() default "";
}

以上是Jdk中提供的元注解,注解说明:

image.png

@Target: 

表明该注解可以应用的java元素类型

Target类型描述
ElementType.TYPE应用于类、接口(包括注解类型)、枚举
ElementType.FIELD应用于属性(包括枚举中的常量)
ElementType.METHOD应用于方法
ElementType.PARAMETER应用于方法的形参
ElementType.CONSTRUCTOR应用于构造函数
ElementType.LOCAL_VARIABLE应用于局部变量
ElementType.ANNOTATION_TYPE应用于注解类型
ElementType.PACKAGE应用于包
ElementType.TYPE_PARAMETER1.8版本新增,应用于类型变量)
ElementType.TYPE_USE1.8版本新增,应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

@Retention:

表明该注解的生命周期

生命周期类型描述
RetentionPolicy.SOURCE编译时被丢弃,不包含在类文件中
RetentionPolicy.CLASSJVM加载时被丢弃,包含在类文件中,默认值
RetentionPolicy.RUNTIME由JVM 加载,包含在类文件中,在运行时可以被获取到

@Documente:

表明该注解标记的元素可以被Javadoc 或类似的工具文档化

@Inherited

表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解

注解解析

一般注解解析,我们可以通过反射机制实现,但是操作起来都比价繁琐;是Spring里面提供了切面编程的注解,可以非常方便的帮助我们来实现注解解析工作,如下

@Aspect
@Component
@Slf4j
public class SystemLogAspect {

    /**
     * 通过注解的方式加入切入点
     **/
    @Pointcut("@annotation(com.hank.mybatisdemo.aop.annotation.LogAnnotation)")
    public void logPointCut() {
        System.out.println("初始化注解切入点...");
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法
        Object method = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        System.out.println("方法执行耗时:" + time);
        /**  做点其他事情,比如记录日志 **/
        try{
            saveSysLog(point, time);
        }catch (Exception e){
            log.error("e={}",e);
        }
        return method;
    }
    
    /** 记录日志 **/
    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
         LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        if(logAnnotation != null){
            //注解上的描述
            log.info("{}-{}",logAnnotation.title(),logAnnotation.action());
        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.info("请求{}.{}耗时{}毫秒",className,methodName,time);
        try {
            //请求的参数
            Object[] args = joinPoint.getArgs();
            String params=null;
            if(args.length!=0){
                params=JSON.toJSONString(args);
            }
            log.info(params);
        } catch (Exception e) {
        }
    }
}

如上代码,我们插入了注解的切面插入点,设置了拦截;可以在环绕兰接触获取到拦截到的点,在方法内可以通过反射机制拿到对应的类,方法名,和参数;同时可以进行分析方法执行的耗时

当然,如果我们这里是Http请求,那么可以使用Spring.web里面的RequestContextHolder工具获取到当前的HttpServletRequest对象,从而去获取对应的请求信息,如下

public static HttpServletRequest getHttpServletRequest() {
    return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}

 

应用验证

前面我们写了相关的代码,接下来我们可以将注解进行应用,如下,只需要在对应的方法明上加入注解即可

  @LogAnnotation(title = "日志模块",action = "查询日志")
    @GetMapping(value = "/list")
    public ResultVO queryLogs(){
        return new ResultVO(0,"操作成功....","");
    }

晚上以上,即可运行验证,每次请求http://localhost:8080/log/list 都会有对应的拦截日志输出,说明注解已经生效


想要了解更多信息,可关注本公众号(一起学开源);或请长按以下二维码添加助手。将拉你加入社区进行更多交流

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起学开源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值