實現背景:需要對service中各個方法進行日誌記錄,包括執行時間,方法用途,以及方法執行結果等。從而知道每個方法對數據庫的改動以及影響。
爲了實現對每個方法用途的記錄,定義了一個註解,然後在註解中存放了方法的用途信息。
定義註解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceLogAnnotation {
public String value();
}
定義AOP advisor:關於@Pointcut的用法請參見這裏
@Component
@Aspect
public class ServiceLogAdvisor{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Autowired
HttpServletRequest httpServletRequest;
@Pointcut("execution(* com.test..*.*(..))")
public void advisorMethod(){
}
// 方法執行完後執行,在配置目錄下以及使用了規定的註解的方法有效
@AfterReturning(returning="result",value="advisorMethod() && @annotation(log)")
public void after(JoinPoint joinPoint,ServiceLogAnnotation log,Object result){
// 方法名稱
String methodName = joinPoint.getSignature().getName();
// 方法參數
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
String[] parameters = methodSignature.getParameterNames();
String userId = "";
String userName = "";
try {
// 在session中獲取登錄信息
// 用戶信息
HttpSession session = httpServletRequest.getSession();
// 獲取管理員ID和管理員名字
userId = (String) session.getAttribute("USERID");
userName = (String) session.getAttribute("USERNAME");
} catch (Exception e) {
userId = "001";
userName = "系統";
e.printStackTrace();
}
// 使用自定義的日誌類(ServiceLog)進行記錄,關於自定義日誌類參見:http://blog.csdn.net/qq_25610165/article/details/70946077
ServiceLog.serviceLogger("調用方法:"+ methodName);
ServiceLog.serviceLogger("方法簽名:" + joinPoint.getSignature());
ServiceLog.serviceLogger("操作人ID:" + userId);
ServiceLog.serviceLogger("操作人姓名:" + userName);
ServiceLog.serviceLogger("方法用途:" + log.value());
ServiceLog.serviceLogger("接收參數:");
for(int i = 0; i < args.length; i++){
ServiceLog.serviceLogger(parameters[i] + ":" + args[i]);
}
ServiceLog.serviceLogger("返回結果:");
if(result instanceof Map){
Map<String,Object> map = (Map<String,Object>)result;
ArrayList objects = (ArrayList)map.get("rows");
for(Object object : objects){
ServiceLog.serviceLogger(object.toString());
}
}else if(result instanceof List){
for(int i = 0; i < ((List)result).size(); i++){
String mapMessage = "";
for (Map.Entry<String, Object> entry : ((Map<String,Object>)((List) result).get(i)).entrySet()) {
mapMessage += entry.getKey() + " = " + entry.getValue() + "\t";
}
ServiceLog.serviceLogger(mapMessage);
}
}else{
ServiceLog.serviceLogger(result);
}
ServiceLog.serviceLogger("方法結束時間:" + sdf.format(new Date()));
}
}
在Spring 上下文中配置AOP(applicationContext.xml)
<!-- AOP配置 -->
<bean id="ServiceAdvisor" class="com.cisdi.tool.serviceLog.ServiceLogAdvisor"></bean>
<aop:aspectj-autoproxy proxy-target-class="true" />
使用:AOP的實現,使用了動態代理模式,只能對public 方法生效,具體使用如下
@ServiceLogAnnotation("測試")
public void test(){
}
只需要在需要使用的方法上,添加上自定義註解即可,同時該類應該存放在ServiceLogAdvisor中@Pointcut中定義的目錄下。
關於自定義的日誌類,請參見作者的另一篇文章《log4j自定義級別並輸出到指定文件》