在日常开发工作中,我们免不了要打印很多log。而大部分需要输出的log又是重复的(例如传入参数,返回值)。
因此,通过AOP方式来进行日志管理可以减少很多代码量,也更加优雅。
Springboot通过AOP方式(@Aspect)和Javassist优雅地进行日志输出管理。
主要使用技术:Aspect,Javassist
package com.xinyartech.erp.system.aop; import java.lang.reflect.Modifier; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import com.xinyartech.erp.core.util.Util; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.NotFoundException; import javassist.bytecode.CodeAttribute; import javassist.bytecode.LocalVariableAttribute; import javassist.bytecode.MethodInfo; /** * 通过spring aop实现service方法执行时间监控 * * @author Lynch * */ @Aspect @Component public class WebLogAop { private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WebLogAop.class); private static ThreadLocal<String> threadLocal = new ThreadLocal<String>(); //public static final String POINT = "execution (* com.xinyartech.erp.*.web.*.*(..))"; @Pointcut("(execution (* com.xinyartech.erp.*.web.*.*(..)))") public void webLog(){ } /** * 前置通知 * @param joinPoint 切点 * @throws Throwable 异常 */ @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { String uuid = Util.getUUID(); threadLocal.set(uuid); String classType = joinPoint.getTarget().getClass().getName(); Class<?> clazz = Class.forName(classType); String clazzName = clazz.getName(); log.info(String.format("[%s] 类名:%s", uuid, clazzName)); String methodName = joinPoint.getSignature().getName(); log.info(String.format("[%s] 方法名:%s", uuid, methodName)); String[] paramNames = getFieldsName(this.getClass(), clazzName, methodName); Object[] args = joinPoint.getArgs(); for(int k=0; k<args.length; k++){ log.info("[" + uuid + "] 参数名:" + paramNames[k] + ",参数值:" + JSON.toJSONString(args[k])); } } /** * 后置通知 * 打印返回值日志 * @param ret 返回值 * @throws Throwable 异常 */ @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(JoinPoint joinPoint, Object ret) throws Throwable { String uuid = threadLocal.get(); String classType = joinPoint.getTarget().getClass().getName(); Class<?> clazz = Class.forName(classType); String clazzName = clazz.getName(); log.info(String.format("[%s] 类名:%s", uuid, clazzName)); String methodName = joinPoint.getSignature().getName(); log.info(String.format("[%s] 方法名:%s", uuid, methodName)); log.info(String.format("[%s] 返回值 : %s", uuid, JSON.toJSONString(ret))); log.info("*****************************************"); } /** * 得到方法参数的名称 * @param cls 类 * @param clazzName 类名 * @param methodName 方法名 * @return 参数名数组 * @throws NotFoundException 异常 */ private static String[] getFieldsName(Class<?> cls, String clazzName, String methodName) throws NotFoundException { ClassPool pool = ClassPool.getDefault(); ClassClassPath classPath = new ClassClassPath(cls); pool.insertClassPath(classPath); CtClass cc = pool.get(clazzName); CtMethod cm = cc.getDeclaredMethod(methodName); MethodInfo methodInfo = cm.getMethodInfo(); CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag); String[] paramNames = new String[cm.getParameterTypes().length]; int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1; for (int i = 0; i < paramNames.length; i++){ paramNames[i] = attr.variableName(i + pos); //paramNames即参数名 } return paramNames; } }
原文地址:https://www.cnblogs.com/linjiqin/p/12218751.html
时间: 2024-11-02 14:24:33