AOP切面记录日志

AOP切面记录日志

一、导包

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
        dependency>

二、写一个注解

/**
 * 用于切面记录日志用的注解,只能加在方法中使用
 * @author ZHAOPINGAN
 */
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
    // 可以在日志中记录该方法的信息,可加可不加
    String value() default "";
}

三、写一个AOP切面类,后面我会讲各个的含义

/**
 * 这是一个记录日志的aop切面
 * @author ZHAOPINGAN
 */
@Aspect
@Component
@Slf4j
public class Log {
    
	// 这里的知识点我后续会讲
    // @Pointcut 这是定义一个切点
    // 目前来说 这个方法没有用,因为我写的 controller 类的方法都是 public 
    // 我这里用了 private ,所以没有匹配的方法
    // 后续可以自己定义一个类的方法
    @Pointcut("execution(private * com.test.controller..*(..))")
    public void pt(){
    }
    // 这里面也可以塞注解
//    @Pointcut("@annotation(com.example.test.utils.MethodLog)")
//    	public void pt(){
//    }

    // 可以用上述的切点 , 也可以使用单个方法的注解记录日志
    // 这里使用了环绕通知,比 @Before 和 @After 更为强大
    // MethodLog 就是 二、写一个注解 中的注解
    @Around("pt() || @annotation(com.test.annotation.MethodLog)")
    public Object log(ProceedingJoinPoint joinPoint){
        Object proceed = null;
        // 获取 class 类,用于记录日志
        Class<?> aClass = joinPoint.getTarget().getClass();
        // 通过该 class 类 生成 Logger
        Logger logger = LoggerFactory.getLogger(aClass);
        try {
            // 获得方法签名(用于获取方法的信息)
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            // 得到方法
            Method method = signature.getMethod();
            // 得到方法上面的注解
            MethodLog annotation = method.getAnnotation(MethodLog.class);
            // 如果方法中的 value 值不为空,就打印
            if (!StringUtils.isEmpty(annotation.value())){
                logger.info("{}",annotation.value());
            }
            // 输出请求参数
            Object[] args = joinPoint.getArgs();
            logger.info(signature.getName() + " 开始 请求参数的参数:{}", JSON.toJSONString(args));
            //执行方法
            proceed = joinPoint.proceed();
            // 输出返回值
            logger.info(signature.getName() + " 结束 返回值:{}",proceed);
        } catch (Throwable e) {
            logger.error("失败原因",e);
        }
        return proceed;
    }

}

@Pointcut参数含义

execution

execution(modifier? ret-type declaring-type?name-pattern(param-pattern) throws-pattern?)

表达式解释:

  • modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符

  • ret-type:匹配返回类型,使用 * 匹配任意类型

  • declaring-type:匹配目标类,省略时匹配任意类型

    • … 匹配包及其子包的所有类
  • name-pattern:匹配方法名称,使用 * 表示通配符

    • * 匹配任意方法
    • set* 匹配名称以 set 开头的方法
  • param-pattern:匹配参数类型和数量

    • () 匹配没有参数的方法
    • (…) 匹配有任意数量参数的方法
    • (*) 匹配有一个任意类型参数的方法
    • (*,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型
  • throws-pattern:匹配抛出异常类型,省略时匹配任意类型

根据上述,解析我写的
// 从后往前看
// com.test.controller..                  controller包下面所以的类
// com.test.controller..*                 controller包下面所以的类的所有方法
// com.test.controller..*(..)             controller包下面所以的类的所有方法且方法的参数随意
// * com.test.controller..*(..)           controller包下面所以的类的所有方法且方法的参数随意 返回值也随意
// private * com.test.controller..*(..))  controller包下面所以的类的所有方法且方法的参数随意 返回值也随意 但修饰符为private 
@Pointcut("execution(private * com.test.controller..*(..))")
public void pt(){
}

@annotation

@annotation(com.example.test.utils.MethodLog)

里面塞注解所在的类就可以了,我的也是塞得注解所在的类,这里就不多加赘述了

四、测试

@RestController
@Slf4j
public class TestController {
    @RequestMapping("/test2")
    @MethodLog
    public JSONObject test2(String id,String cid){
        log.info(id);
        log.info(cid);
        return EcpResponseUtil.success("成功","????????");
    }
}

AOP切面记录日志_第1张图片

参考博文:Spring AOP切点表达式(Pointcut)详解

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