通过AOP拦截打印日志,出入参数

import java.lang.reflect.Modifier;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

/**@Description
 哪个资方需要输出日志,自己到**-config工程下的spring-commons.xml配置
<!-- 日志打印 -->
<bean id="aopLog" class="com.XXXXXXX.AopLog"/>
 * @author : 陈惟鲜 danger
 * @Date : 2018年8月9日 下午5:59:55
 *
 */
@Aspect
public class AopLog {

    private Logger logger = LoggerFactory.getLogger(getClass());
    /**拦截所有controller包下的方法*/
    @Pointcut("execution(* com.sinaif.king..controller..*.*(..))")
    private void controllerMethod(){}//定义一个切入点  

    /**拦截所有service包下的方法*/
    @Pointcut("execution(* com.sinaif.king..service..*.*(..))")
    private void serviceMethod(){}//定义一个切入点  

//    // 1、前置通知: 在目标方法开始之前执行(就是要告诉该方法要在哪个类哪个方法前执行)
//    @Before("controllerMethod() || serviceMethod()")
//    public void beforeMethod(JoinPoint joinPoint) {
//         String methodName = joinPoint.getSignature().getName();
//         String className = joinPoint.getTarget().getClass().getName();
//         String msgInfo = "【" + className + "." + methodName + "】";
//         logger.info(msgInfo + "......start..........");
//    }
//
//    // 2、后置通知:在目标方法执行后(无论是否发生异常),执行的通知
//    // 注意,在后置通知中还不能访问目标执行的结果!!!,执行结果需要到返回通知里访问
//    @After("controllerMethod() || serviceMethod()")
//    public void afterMethod(JoinPoint joinPoint) {
//         String className = joinPoint.getTarget().getClass().getName();
//         String methodName = joinPoint.getSignature().getName();
//         String msgInfo = "【" + className + "." + methodName + "】";
//         logger.info(msgInfo + "...............end.");
//    }

    /**
     * @Description : 日志打印
     * @author : 陈惟鲜 danger
     * @Date : 2018年8月8日 下午5:29:47
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("controllerMethod() || serviceMethod()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        String msgInfo = "@aop["+point.getSignature().getDeclaringTypeName()+"."+point.getSignature().getName()+"]"; // 所在的类.方法
        String requestStr = getRequestParam(point);
        requestStr = parameterHandle(requestStr, 10000);
        logger.info(msgInfo + "start.输入参数:" + requestStr);
        long startTime = System.currentTimeMillis();// 开始时间
        Object result = null;
        try{
            // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
            result = point.proceed();// result的值就是被拦截方法的返回值
        }catch(Exception e){
            throw e;
        }finally{
            long handleTime = System.currentTimeMillis()-startTime;// 开始时间
            String responseStr = result==null?"无": JSON.toJSONString(result);
            responseStr = parameterHandle(responseStr, 10000);

            StringBuffer endString = new StringBuffer(100);
            endString.append(msgInfo).append("end.");
            endString.append("耗时(" + handleTime + "ms)");
            endString.append("输出参数:").append(responseStr);

            logger.info(endString.toString());
        }
        return result;
    }

    /**
     * @Description : 参数处理,超过指定长度字符的,只显示1000...
     * @author : 陈惟鲜 danger
     * @Date : 2018年8月10日 上午11:44:11
     * @param paramStr
     * @param strlength
     * @return
     */
    private String parameterHandle(String paramStr, int strlength){
        if (paramStr.length() > strlength){
            paramStr = paramStr.substring(0, 1000) + "...";
        }
        if (paramStr.length() > 10){
            paramStr = "[" + paramStr + "]";
        }
        return paramStr;
    }

    /***
     * @Description : 获取请求参数
     * @author : 陈惟鲜 danger
     * @Date : 2018年8月9日 下午3:47:08
     * @param point
     * @return
     */
    private String getRequestParam(ProceedingJoinPoint point){
        String class_name = point.getTarget().getClass().getName();
        String method_name = point.getSignature().getName();
        /**
         * 获取方法的参数值数组。
         */
        Object[] methodArgs = point.getArgs();

        String[] paramNames = null;
        // 结果
        String requestStr = "";
        /**
         * 获取方法参数名称
         */
         try {
            paramNames = getFieldsName(class_name, method_name);
            requestStr = logParam(paramNames, methodArgs);
        } catch (Exception e) {
            requestStr = "获取参数失败";
        }
        return requestStr;
    }

    /**
     * 使用javassist来获取方法参数名称
     * @param class_name    类名
     * @param method_name   方法名
     * @return
     * @throws Exception
     */
    private String[] getFieldsName(String class_name, String method_name) throws Exception {
        Class<?> clazz = Class.forName(class_name);
        String clazz_name = clazz.getName();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        pool.insertClassPath(classPath);

        CtClass ctClass = pool.get(clazz_name);
        CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if(attr == null){
            return null;
        }
        String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
        for (int i=0;i<paramsArgsName.length;i++){
            paramsArgsName[i] = attr.variableName(i + pos);
        }
        return paramsArgsName;
    }

    /**
     * 判断是否为基本类型:包括String
     * @param clazz clazz
     * @return  true:是;     false:不是
     */
    private boolean isPrimite(Class<?> clazz){
        if (clazz.isPrimitive() || clazz == String.class){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 打印方法参数值  基本类型直接打印,非基本类型需要重写toString方法
     * @param paramsArgsName    方法参数名数组
     * @param paramsArgsValue   方法参数值数组
     */
    private String logParam(String[] paramsArgsName,Object[] paramsArgsValue){
        if(ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)){
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (int i=0;i<paramsArgsValue.length;i++){
            //参数名
            String name = paramsArgsName[i];
            //参数值
            Object value = paramsArgsValue[i];
            buffer.append(name +" = ");
            if(isPrimite(value.getClass())){
                buffer.append(value + "  ,");
            }else {
                buffer.append(value.toString() + "  ,");
            }
        }
        return buffer.toString();
    }
}

原文地址:https://www.cnblogs.com/a393060727/p/9454281.html

时间: 2024-10-21 18:23:18

通过AOP拦截打印日志,出入参数的相关文章

Spring Boot- 设置拦截打印日志

import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springfra

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码 https://www.cnblogs.com/newAndHui/p/11771035.h

springboot aop + logback + 统一异常处理 打印日志

1.src/resources路径下新建logback.xml 控制台彩色日志打印 info日志和异常日志分不同文件存储 每天自动生成日志 结合myibatis方便日志打印(debug模式) <?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日志文件的存储地址 可以在LogBack 的配置中使用相对路径--> &

aop打印日志

首先在资源目录下创建logback.xml文件 文件的内容 <?xml version="1.0" encoding="UTF-8"?> <configuration> <!--======================================= 本地变量 ======================================== --> <!--在没有定义${LOG_HOME}系统变量的时候,可以设置此本地

用户操作拦截并作日志记录--自定义注解+AOP拦截

作为运营除了处理系统生产问题,还要处理大量的用户上报事件,这部分工作占用了大量的人力.所有考虑把一部分事件查询处理做成一个自助平台,让用户自行核查处理.于是就有了用户自助系统.考虑到如何计量这个工具平台具体的实现价值,需要做用户操作统计才能给出可信服的数据. 以上就是本文的背景.自助系统的架构就是传统的springmvc+spinrg+mybatis+oracle.想到日志记录首先想到的就是AOP拦截处理.网上相关的技术贴很多.简单的小项目遇到的问题一般度娘都能给解决了~\(≧▽≦)/~ 自定义

spring面向切面aop拦截器

spring中有很多概念和名词,其中有一些名字不同,但是从功能上来看总感觉是那么的相似,比如过滤器.拦截器.aop等. 过滤器filter.spring mvc拦截器Interceptor .面向切面编程aop,实际上都具有一定的拦截作用,都是拦截住某一个面,然后进行一定的处理. 在这里主要想着手的是aop,至于他们的比较,我想等三个都一一了解完了再说,因此这里便不做过多的比较. 在我目前的项目实践中,只在一个地方手动显示的使用了aop,那便是日志管理中对部分重要操作的记录. 据我目前所知,ao

Spring aop 记录操作日志 Aspect

前几天做系统日志记录的功能,一个操作调一次记录方法,每次还得去收集参数等等,太尼玛烦了.在程序员的世界里,当你的一个功能重复出现多次,就应该想想肯定有更简单的实现方法.于是果断搜索各种资料,终于搞定了,现在上代码 环境: SpringMvc + myBatis jar包 :      (aspect.jar也行,我原来项目中有,便没有替换了) 1.自定义注解类   ArchivesLog.java(获取Controller描述用的) package com.noahwm.uomp.archive

使用AOP拦截器获取一次请求流经方法的调用次数和调用耗时

引语 作为工程师,不能仅仅满足于实现了现有的功能逻辑,还必须深入认识系统.一次请求,流经了哪些方法,调用了多少次DB操作,多少次API操作,多少次IO操作,多少CPU操作,各耗时多少 ? 开发者必须知道这些运行时数据,才能对系统的运行有更深入的理解,更好滴提升系统的性能和稳定性. 完成一次订单导出任务,实际上是一个比较复杂的过程:需要访问ES 来查询订单,调用 API 及访问 Hbase 获取订单详情数据,写入和上传报表文件,更新数据库,上报日志数据等:在大流量导出的情形下,采用批量并发策略,多

Spring MVC 中使用AOP 进行统一日志管理--XML配置实现

1.介绍 上一篇博客写了使用AOP进行统一日志管理的注解版实现,今天写一下使用XML配置实现版本,与上篇不同的是上次我们记录的Controller层日志,这次我们记录的是Service层的日志.使用的工程还是原来的那个,具体的Spring mvc 工程搭建暂不介绍.上篇记录controller层日志的时候是将切面类组件叫给spring MVC 进行管理,因为 controller 也是交给spring MVC进行管理的,但是记录service 层日志的时候应该就应该再spring 容器中进行了,