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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM