springboot+aspectj实现自定义注解
1.添加maven依赖
<!--使用springboot+aspect,此依赖里面包含了aspectjweaver依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.15.RELEASE</version>
</dependency>
2.添加自定义注解(ShadowLog)
- 自定义注解需要添加两个注解,Retention(此例使用RetentionPolicy.RUNTIME)和Target(此例使用ElementType.METHOD,如不添加Target则可以使用在除TYPE_PARAMETER和TYPE_USE外的任何地方)
- Retention作用是用于标明生效的时机,它必须设置value值,value为枚举类型RetentionPolicy,包含SOURCE(源码注解)、CLASS(编译时注解)、RUNTIME(运行时注解)三种
- Target表示注解的使用位置,同样必须设置value值,值为ElementType数组,可在多个地方设置,如TYPE(作用在类、接口、注解、枚举上)、FIELD(作用在属性声明、枚举常量上)、METHOD(作用在方法上)、PARAMETER(作用在方法参数上)、CONSTRUCTOR(作用在构造方法上)、ANNOTATION_TYPE(作用在注解上)、LOCAL_VARIABLE(作用在本地变量上)、PACKAGE(作用在包上)、TYPE_PARAMETER(1.8新增,暂不清楚使用场景,后续补上)、TYPE_USE(1.8新增,暂不清楚使用场景,后续补上)
package com.shadow.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类 描 述:用于记录方法日志,包含请求参数、调用时间、调用次数
* 创 建 人:Shadow
* 创建时间:2020年10月01日 22时40分
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ShadowLog {
}
3.添加切面类
package com.shadow.common.annotation;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
/**
* 类 描 述:
* 创 建 人:Shadow
* 创建时间:2020年10月01日 22时45分
*/
@Aspect
@Component
@Slf4j
public class ShadowLogAspect {
/**
* 定义切点,作用在使用了{@link ShadowLog}注解的地方
*/
@Pointcut("@annotation(com.shadow.common.annotation.ShadowLog)")
public void logPointCut() {
}
/**
* 记录参数、返回值、方法调用时间
* Around和logPointCut可写一起,如@Around("@annotation(com.shadow.common.annotation.ShadowLog)")
*/
@Around("logPointCut()")
public Object process(ProceedingJoinPoint point) throws Throwable {
//获取方法参数
Object[] args = point.getArgs();
//获取方法名
String methodName = point.getSignature().getName();
//获取所在类名
String className = point.getTarget().getClass().getName();
//记录参数
try {
log.info("{} | args:{}", methodName, JSONUtil.toJsonStr(args));
} catch (Exception e) {
log.error("注解打印参数日志错误:{}.{}", className, methodName);
}
//记录方法调用时间
long start = System.currentTimeMillis();
Object result = point.proceed();
long end = System.currentTimeMillis();
//记录返回值
try {
log.debug("{} | {}ms,return:{}", methodName, (end - start), JSONUtil.toJsonStr(result));
} catch (Exception e) {
log.error("注解打印返回值日志错误:{}.{},e:{}", className, methodName, e);
}
return result;
}
}
4.添加注解,测试结果,如下为测试代码
/**
* 测试方法
* @param jsonObject
* @return
*/
@ShadowLog
@PostMapping("add")
public R add(@RequestBody JSONObject jsonObject){
//休眠100ms,查看效果
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return R.ok();
}
请求参数
请求结果