功能:不但可以打印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: {}.{} {}, params: {}", targetClassName, methodName, desc, 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: {}, cost: {}ms", FastJsonUtil.toJson(result), 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;
}