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