springboot2 AOP切面实现打印任意类的方法入参、出参、耗时

功能:不但可以打印Controller方法里的入参和出参,也能打印Service类或任意一个类里的方法入参和出参。

注意: AOP默认如果同一个类有A方法、B方法,如果A调用了B, 则B方法上的注解不生效,必须是非同类的发起的调用方法注解才生效。

自定义注解 printLog
/**
 * 日志切面注解
 *
 * @author zhaoyang10
 * @date 2020/7/27
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface PrintLog {

    /**
     * 日志方法描述信息
     */
    String info() default "";
}

注解切面实现

import com.xx.xx.fms.common.util.FastJsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Profile;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 打印日志切面
 *
 * @author zhaoyang10
 * @date 2020/7/27
 */
@Slf4j
@Aspect
@Component
@Profile({"dev", "test", "uat"})
public class PrintLogAspect {

    private static ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();

    @Pointcut("@annotation(com.weibo.bop.fms.common.support.log.PrintLog)")
    public void printLog() {
        // do nothing
    }

    @Before("printLog()")
    public void doBefore(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String targetClassName = signature.getDeclaringType().getSimpleName();
        String methodName = signature.getName();

        PrintLog printLog = signature.getMethod().getAnnotation(PrintLog.class);
        String desc = printLog.info();

        log.info("Method info: {}.{} {}", targetClassName, methodName, desc);
        log.info("Method params: {}", FastJsonUtil.toJson(getFieldsName(joinPoint)));
    }

    @Around("printLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        Object result = proceedingJoinPoint.proceed();

        log.info("Method result: {}", FastJsonUtil.toJson(result));
        log.info("Method cost: {} ms", System.currentTimeMillis() - startTime);
        return result;
    }

    /**
     * 获取参数列表
     */
    private static Map<String, Object> getFieldsName(JoinPoint joinPoint) {
        // 参数值
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String[] parameterNames = pnd.getParameterNames(method);
        if (parameterNames != null) {
            Map<String, Object> paramMap = new HashMap<>(parameterNames.length);
            for (int i = 0; i < parameterNames.length; i++) {
                paramMap.put(parameterNames[i], args[i]);
            }
            return paramMap;
        }
        return Collections.emptyMap();
    }
}

使用示例

// Controller方法
@PrintLog(info = "测试方法test2")
@GetMapping("/test/test2")
public ApiResult<String> test2(@RequestParam String name, String age) {

	return ApiResult.ok();
}

// 非Controller方法
@PrintLog(info = "测试方法list")
public TestRepDTO list(TestReqDTO dto){
	ThreadUtil.sleep(3000);
	
	TestRepDTO repDTO = new TestRepDTO();
	// do something
	return repDTO;
}

你可能感兴趣的:(springcloud2)