因項目需要,要求在方法執行前後列印參數及傳回值,上網找了一個可用的,利用aop做的工具,稍作修改後,把入參,出參放到一個json裡,成果跟大家分享一下。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component //聲明元件
@Aspect //聲明切面
@ComponentScan //元件自動掃描
@EnableAspectJAutoProxy //spring自動切換JDK動态代理和CGLIB
public class LogRecordAspect {
private Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);
public JSONObject printMethodParams(JoinPoint point,String temp){
if(point == null){
return new JSONObject();
}
String class_name = point.getTarget().getClass().getName();
String method_name = point.getSignature().getName();
//重新定義日志
logger = LoggerFactory.getLogger(point.getTarget().getClass());
logger.info("class_name = {},temp:"+temp,class_name);
logger.info("method_name = {},temp:"+temp,method_name);
JSONObject paramJson = new JSONObject();
paramJson.put("class_name",class_name);
paramJson.put("method_name",method_name);
paramJson.put("temp",temp);
Object[] method_args = point.getArgs();
try {
//擷取方法參數名稱
String[] paramNames = getFieldsName(class_name, method_name);
//列印方法的參數名和參數值
String param_name = logParam(paramNames,method_args);
paramJson.put("param_name",JSONObject.parse(param_name));
} catch (Exception e) {
e.printStackTrace();
}
return paramJson;
}
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];
// 如果是靜态方法,則第一就是參數
// 如果不是靜态方法,則第一個是"this",然後才是方法的參數
// 我接口中沒有寫public修飾詞,導緻我的數組少一位參數,是以再往後一位,原本應該是 XX ? 0 : 1
int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 1 : 2;
for (int i=0;i
paramsArgsName[i] = attr.variableName(i+pos);
}
return paramsArgsName;
}
private boolean isPrimite(Class> clazz){
if (clazz.isPrimitive() || clazz == String.class){
return true;
}else {
return false;
}
}
private String logParam(String[] paramsArgsName,Object[] paramsArgsValue){
StringBuffer buffer = new StringBuffer();
if(ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)){
buffer.append("該方法沒有參數");
return buffer.toString();
}
for (int i=0;i
//參數名
String name = paramsArgsName[i];
//參數值
Object value = paramsArgsValue[i];
buffer.append("\""+name+"\":");
if(isPrimite(value.getClass())){
buffer.append("\""+value+"\",");
}else {
buffer.append(JSON.toJSONString(value)+",");
}
}
return "{"+buffer.toString().substring(0,buffer.toString().length()-1)+"}";
}
@Around("execution(* com.abc.service.*.many*(..))")
public Object around(ProceedingJoinPoint pj) throws Throwable {
Long temp = System.currentTimeMillis();
JSONObject paramJson = this.printMethodParams(pj,String.valueOf(temp));
logger.info("請求前:"+paramJson.toString());
Object retVal = pj.proceed();
JSONObject returnJson = new JSONObject();
returnJson.put("temp",temp);
returnJson.put("class_name",paramJson.get("class_name"));
returnJson.put("method_name",paramJson.get("method_name"));
returnJson.put("return_name",retVal);
logger.info("請求後:"+returnJson.toString());
return retVal;
}
}
備注:
1.ProceedingJoinPoint是JoinPoint的子類。
2.around方法應該有傳回值,拿了沒放回去後果就是丢失傳回值....
public Object around(……){
……
return retVal;
}