須要對一些事物的操做進行日誌記錄,若是在service內進行記錄,大量的代碼重複,而且維護比較麻煩。因此採用AOP的方式對service進行攔截。使用自定義註解的目的則是判斷是否須要記錄日誌和傳遞額外的信息。html
本次解決方案十分感謝博主-跳刀的兔子的博文 本文絕大部分參考與本文,略有不一樣,因此作一些整理,博主的文章更詳細一些。java
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface LogWrite { /** *@param 模塊名字 */ String modelName() default ""; /** *@param 操做類型 */ String option(); }
其中@Target註解用於描述該註解的範圍,咱們須要註解的方法,因此值爲METHOD,相關含義以下表:spring
取值 含義mybatis
CONSTRUCTOR 描述構造器mvc
FIELD 描述域this
LOCAL_VARIABLE 用於描述局部變量spa
METHOD 用於描述方法.net
PACKAGE 用於描述包日誌
PARAMETER 用於描述參數code
TYPE 用於描述類或接口
@Retention 用於描述註解的生命週期(即:被描述的註解在什麼範圍內有效),其取值有:
取值 含義
SOURCE 在源文件中有效(即源文件保留)
CLASS 在 class 文件中有效(即 class 保留)
RUNTIME 在運行時有效(即運行時保留)
@Documented 在默認的狀況下javadoc命令不會將咱們的annotation生成再doc中去的,因此使用該標記就是告訴jdk讓它也將annotation生成到doc中去
@Inherited 好比有一個類A,在他上面有一個標記annotation,那麼A的子類B是否不用再次標記annotation就能夠繼承獲得呢,答案是確定的
配置AOP,我使用的是利用註解的方式來配置AOP,方法有不少,就不詳細說了。
使用的是@Around 環繞通知,由於須要記錄該方法是否被執行成功了。
實現@Around方法中,記錄日誌: 獲取攔截的方法,判斷該方法是否含有自定義註解,若是沒有的則不進行記錄,不然,按照本身的方式進行記錄。 我主要記錄的是操做的方法,所屬模塊,以及全部參數所構成的Json字符串。
@Aspect @Component public class SnapshotLogWriteService { private LogService logService; public LogService getLogService() { return logService; } //自動注入日誌記錄service @Autowired public void setLogService(LogService logService) { this.logService = logService; } //環繞通知方法 @Around("execution(* unkeltao.service.*.*(..))") public Object doWriteLog(ProceedingJoinPoint pjp) throws Throwable { System.err.println("攔截方法,進入日誌記錄"); // 攔截的實體類 Object target = pjp.getTarget(); // 攔截的方法名稱 String methodName = pjp.getSignature().getName(); // 攔截的方法參數 Object[] args = pjp.getArgs(); // 攔截的放參數類型 Class[] parameterTypes = ((MethodSignature) pjp.getSignature()) .getMethod().getParameterTypes(); Object object = null; //須要轉換成Json的HashMap Map<String, Object> maps = new HashMap<String, Object>(); Map<String, Object> parammaps = new HashMap<String, Object>(); // 得到被攔截的方法 Method method = target.getClass().getMethod(methodName, parameterTypes); if (null != method) { // 判斷是否包含自定義的註解 if (method.isAnnotationPresent(MyAnnotation.class)) { // 獲取自定義註解實體 MyAnnotation myAnnotation = method .getAnnotation(MyAnnotation.class); //日誌類實體類 OptionLog log = new OptionLog(); log.setUserid(myAnnotation.userid()); log.setModelname(myAnnotation.modelName()); log.setOp(myAnnotation.option()); maps.put("方法名", method.getName()); parammaps.put("方法名", method.getName()); //循環得到全部參數對象 for(int i=0; i<args.length; i++){ if (null != args[i]) { parammaps.put("args["+i+"]", args[i]); } else { parammaps.put("args["+i+"]", "空參數"); } } maps.put("參數", parammaps); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); maps.put("操做時間", sdf.format(new Date())); // 獲取服務運行結果 try { object = pjp.proceed();// 執行該方法 maps.put("狀態", "成功"); log.setStatus(1); } catch (Exception e) { System.err.println(e.getMessage()); maps.put("狀態", "失敗"); log.setStatus(0); log.setComments(e.getMessage()); } //將參數轉化爲Json字符串 log.setJs(new JSONObject(maps).toJSONString()); log.setOptime(new Date()); System.err.println(new JSONObject(maps).toJSONString()); //記錄相關日誌 if (null != logService) { try { if(1 == logService.Save(log)){ System.err.println("日誌記錄成功"); } else{ System.err.println("日誌記錄失敗"); } } catch (Exception e) { e.printStackTrace(); } } else{ System.err.println("自動注入失敗,日誌未記錄"); } } else { // 沒有包含該註解則不進行其餘處理 object = pjp.proceed();// 執行該方法 } } else { // 不須要攔截,直接運行 object = pjp.proceed(); // 執行該方法 } return object; } }
原文地址: http://www.UnkelTao.com/blog/2014/07/22/spring-plus-springmvc-plus-mybatis-aop/