码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-08-10 13:09:25      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:else   art   prim   import   前置   sys   xxx   exec   owa   

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();
    }
}

 

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

标签:else   art   prim   import   前置   sys   xxx   exec   owa   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!