Aop+自定义注解实现查看操作日志

一、自定义注解

1、注解分为元注解和自定义注解,而元注解可以进入到你经常使用到的springboot注解中查看,在注解源码最上方,可以看到有这三个注解出现,而这三个注解是jdk提供的,包是package java.lang.annotation;
在这里插入图片描述
(1)@Target: 指明注解的作用域,也就是可以指定自定义注解用于什么位置,类、方法、字段,可以指定多种。
(2) @Retention 指定自定义注解在什么时候生效,也就是指定他的生命周期,首先要明白要跑一个java文件,是先编译变为.class文件,也就是字节码文件,然后再通过jvm去执行这个文件,而你经常听到的运行时异常的运行时,其实就是在执行这个.class文件出现的异常,而编译时异常则是在编译为.class时出现异常。详情查看
现在回到这个注解,这三种参数都是什么?
其实常用的就是 RUNTIME ,这是指在经过编译之后,通过jvm执行之后仍然会保留着,而 Source 是指在编译时便被丢弃;而 CLASS 则是在编译的时候会保留在.class文件中,但是通过jvm执行时会被丢弃。
Aop+自定义注解实现查看操作日志_第1张图片
(3) @Documented: 这个起到一个标注作用,下面是源码的解释
Aop+自定义注解实现查看操作日志_第2张图片
2、自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CustomAnnotation {
}

二、使用AOP查看操作日志

先明白思路,要实现操作日志,也就是我们需要在他进行操作的过程中获取他的请求、他请求调用的全限定名、传入的参数,最后返回的参数是什么,也就是在他操作的整个过程,咱们都需要参与,那就是用到了注解 @Around 详情查看

package com.example.demo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class AopLog {
    private Logger logger = LoggerFactory.getLogger(this.getClass());//slf4j的日志打印
    ThreadLocal<Long> startTime = new ThreadLocal<>();//创建一个子线程来存时间

    @Around("@annotation(CustomAnnotation)")
    public Object myLogger(ProceedingJoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());//计时,存下当前时间
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//绑定当前线程的请求的对象
        HttpServletRequest request = attributes.getRequest();
        String className = joinPoint.getSignature().getDeclaringTypeName();//获取请求的类的完全限定名
        String methodName = joinPoint.getSignature().getName();//请求的方法
        Object[] array = joinPoint.getArgs();//传入的参数
        ObjectMapper mapper = new ObjectMapper();
        //执行函数前打印日志
        logger.info("调用前:{}:{},传递的参数为:{}", className, methodName, mapper.writeValueAsString(array));
        logger.info("URL:{}", request.getRequestURL().toString());
        logger.info("IP地址:{}", request.getRemoteAddr());
        //调用整个目标函数执行
        Object obj = joinPoint.proceed();
        //执行函数后打印日志
        logger.info("调用后:{}:{},返回值为:{}", className, methodName, mapper.writeValueAsString(obj));
        logger.info("耗时:{}ms", System.currentTimeMillis() - startTime.get());
        return obj;
    }
}

你可能感兴趣的:(springboot,java,spring,boot)