利用AOP,實現log列印方法名和入參
阿新 • • 發佈:2021-11-13
1 package com.xxx.aspect; 2 3 import cn.hutool.core.util.ArrayUtil; 4 import com.alibaba.fastjson.JSON; 5 import javassist.ClassClassPath; 6 import javassist.ClassPool; 7 import javassist.CtClass; 8 import javassist.CtMethod; 9 import javassist.bytecode.CodeAttribute; 10 import javassist.bytecode.LocalVariableAttribute;11 import javassist.bytecode.MethodInfo; 12 import lombok.extern.slf4j.Slf4j; 13 import org.aspectj.lang.JoinPoint; 14 import org.aspectj.lang.annotation.Aspect; 15 import org.aspectj.lang.annotation.Before; 16 import org.aspectj.lang.annotation.Pointcut; 17 import org.aspectj.lang.reflect.MethodSignature;18 import org.springframework.stereotype.Component; 19 20 import java.lang.reflect.Modifier; 21 import java.util.LinkedHashMap; 22 import java.util.Map; 23 24 /** 25 * service 日誌列印 26 * 27 * @author kyj 28 * @date 2021/11/4 10:25 29 */ 30 @Slf4j 31 @Aspect 32 @Component 33 public classServiceLogAspect { 34 /** 35 * Pointcut解釋 36 * (bean(*ServiceImpl) || bean(*Service)) 37 * 所有以 ServiceImpl、Service 結尾的 bean 38 * <p> 39 * !(execution(public * com.xxx.activity..*.syn*(..)) || execution(public * com.xxx.activity..*.past*(..))) 40 * 不選中 com.xxx.activity 包以及子包下 syn或past開頭的public方法 41 * <p> 42 * (within(com.xxx.activity.coupon..*) || within(com.xxx.activity.member..*) || within(com.xxx.activity.integral..*)) 43 * 選中com.xxx.activity 下的 coupon、member、integral 包以及子包 44 */ 45 @Pointcut("(bean(*ServiceImpl) || bean(*Service)) && " + 46 "!(execution(public * com.xxx.activity..*.syn*(..)) || execution(public * com.xxx.activity..*.past*(..))) && " + 47 "(within(com.xxx.activity.coupon..*) || within(com.xxx.activity.member..*) || within(com.xxx.activity.integral..*))") 48 public void pointCut() { 49 } 50 51 /** 52 * 前置 53 * 列印類路徑和引數 54 * 55 * @param joinPoint 56 */ 57 @Before("pointCut()") 58 public void doBefore(JoinPoint joinPoint) { 59 try { 60 // 當前切入的類 61 Class<?> clazz = joinPoint.getTarget().getClass(); 62 // 當前執行的方法所屬的類、包 63 String className = clazz.getName(); 64 65 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 66 // 當前執行的方法名稱 67 String methodName = signature.getName(); 68 69 // 引數名 70 String[] fieldsName = getFieldsName(clazz, methodName); 71 // 入參 72 String param = getParam(fieldsName, joinPoint.getArgs()); 73 74 log.warn("\n{}\n{}() <= {}", className, methodName, param); 75 } catch (Exception e) { 76 log.error("{}", e.getMessage()); 77 } 78 } 79 80 /** 81 * 獲取入參並轉成json 82 * 83 * @param fieldsName 引數名 84 * @param fieldsValue 引數值 85 * @return 86 */ 87 private String getParam(String[] fieldsName, Object[] fieldsValue) { 88 if (ArrayUtil.isEmpty(fieldsName)) { 89 return ""; 90 } 91 92 Map<String, Object> result = new LinkedHashMap<>(fieldsName.length); 93 for (int i = 0; i < fieldsName.length; i++) { 94 result.put(fieldsName[i], JSON.toJSONString(fieldsValue[i])); 95 } 96 97 return JSON.toJSONString(result); 98 } 99 100 /** 101 * 獲取引數名 102 * 103 * @param clazz 104 * @param methodName 105 * @return 106 * @throws Exception 107 */ 108 private String[] getFieldsName(Class<?> clazz, String methodName) throws Exception { 109 String clazzName = clazz.getName(); 110 ClassPool pool = ClassPool.getDefault(); 111 ClassClassPath classPath = new ClassClassPath(clazz); 112 pool.insertClassPath(classPath); 113 114 CtClass ctClass = pool.get(clazzName); 115 CtMethod ctMethod = ctClass.getDeclaredMethod(methodName); 116 MethodInfo methodInfo = ctMethod.getMethodInfo(); 117 CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); 118 LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag); 119 if (attr == null) { 120 return null; 121 } 122 String[] paramsArgsName = new String[ctMethod.getParameterTypes().length]; 123 int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1; 124 for (int i = 0; i < paramsArgsName.length; i++) { 125 paramsArgsName[i] = attr.variableName(i + pos); 126 } 127 return paramsArgsName; 128 } 129 }