1. 程式人生 > >通過AOP攔截打印日誌,出入參數

通過AOP攔截打印日誌,出入參數

耗時 日誌 觸發 params mod XML apach request 不能

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攔截打印日誌,出入參數