1. 程式人生 > >日誌攔截AOP,當執行拋異常時@AfterThrowing執行了沒效果

日誌攔截AOP,當執行拋異常時@AfterThrowing執行了沒效果


使用Spring的AOP進行日誌記錄,對應的程式碼為

  1. package cn.tiansu.eway.logAop;  
  2. import java.lang.reflect.Method;  
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5. import javax.inject.Inject;  
  6. import org.apache.shiro.SecurityUtils;  
  7. import org.aspectj.lang.JoinPoint;  
  8. import org.aspectj.lang.ProceedingJoinPoint;  
  9. import org.aspectj.lang.annotation.AfterThrowing;  
  10. import org.aspectj.lang.annotation.Around;  
  11. import org.aspectj.lang.annotation.Aspect;  
  12. import org.aspectj.lang.annotation.Pointcut;  
  13. import org.slf4j.Logger;  
  14. import org.slf4j.LoggerFactory;  
  15. import org.springframework.core.Ordered;  
  16. import org.springframework.stereotype.Component;  
  17. import cn.tiansu.eway.annotation.SystemLog;  
  18. import cn.tiansu.eway.entity.LogFormMap;  
  19. import cn.tiansu.eway.mapper.LogMapper;  
  20. import cn.tiansu.eway.util.Common;  
  21. /** 
  22.  * 切點類 
  23.  * 
  24.  * @author LJN 
  25.  * @since 2015-05-05 Pm 20:35 
  26.  * @version 1.0 
  27.  */
  28. @Aspect
  29. @Component
  30. publicclass LogAopAction <span style="color:#ff0000;">implements Ordered</span>{  
  31.     // 本地異常日誌記錄物件
  32.     privatestaticfinal Logger logger = LoggerFactory.getLogger(LogAopAction.class);  
  33.     @Inject
  34.     private LogMapper logMapper;  
  35.     // Controller層切點
  36.     @Pointcut("@annotation(cn.tiansu.eway.annotation.SystemLog)")  
  37.     publicvoid controllerAspect() {  
  38.     }  
  39.     /** 
  40.      * 操作異常記錄 
  41.      * 
  42.      * @descript 
  43.      * @param point 
  44.      * @param e 
  45.      * @author LJN 
  46.      * @date 2015年5月5日 
  47.      * @version 1.0 
  48.      */
  49.     @AfterThrowing(pointcut = "controllerAspect()", throwing = "e")  
  50.     publicvoid doAfterThrowing(JoinPoint point, Throwable e) {  
  51.         LogFormMap logForm = new LogFormMap();  
  52.         Map<String, Object> map = null;  
  53.         String user = null;  
  54.         String ip = null;  
  55.         Long start = 0L;  
  56.         Long end = 0L;  
  57.         Long time = 0L;  
  58.         try {  
  59.             ip = SecurityUtils.getSubject().getSession().getHost();  
  60.         } catch (Exception ee) {  
  61.             ip = "無法獲取登入使用者Ip";  
  62.         }  
  63.         try {  
  64.             map = getControllerMethodDescription(point);  
  65.             // 登入名
  66.             user = SecurityUtils.getSubject().getPrincipal().toString();  
  67.             if (Common.isEmpty(user)) {  
  68.                 user = "無法獲取登入使用者資訊!";  
  69.             }  
  70.         } catch (Exception ee) {  
  71.             user = "無法獲取登入使用者資訊!";  
  72.         }  
  73.         try {  
  74.             start = System.currentTimeMillis();  
  75.             end = System.currentTimeMillis();  
  76.             time = end - start;  
  77.             logForm.put("accountName", user);  
  78.             logForm.put("module", map.get("module"));  
  79.             logForm.put("methods", map.get("methods"));  
  80.             logForm.put("description""執行失敗,原因:" + e);  
  81.             logForm.put("actionTime", time);  
  82.             logForm.put("userIP", ip);  
  83.             logForm.put("type", map.get("type"));  
  84.             logMapper.addEntity(logForm);  
  85.         } catch (Exception e1) {  
  86.             e1.printStackTrace();  
  87.         }  
  88.     }  
  89.     /** 
  90.      * 前置通知 用於攔截Controller層記錄使用者的操作 
  91.      * 
  92.      * @param joinPoint 
  93.      *            切點 
  94.      */
  95.     @Around("controllerAspect()")  
  96.     public Object doController(ProceedingJoinPoint point) {  
  97.         Object result = null;  
  98.         // 執行方法名
  99.         String methodName = point.getSignature().getName();  
  100.         String className = point.getTarget().getClass().getSimpleName();  
  101.         LogFormMap logForm = new LogFormMap();  
  102.         Map<String, Object> map = null;  
  103.         String user = null;  
  104.         Long start = 0L;  
  105.         Long end = 0L;  
  106.         Long time = 0L;  
  107.         String ip = null;  
  108.         try {  
  109.             ip = SecurityUtils.getSubject().getSession().getHost();  
  110.         } catch (Exception e) {  
  111.             ip = "無法獲取登入使用者Ip";  
  112.         }  
  113.         try {  
  114.             // 登入名
  115.             user = SecurityUtils.getSubject().getPrincipal().toString();  
  116.             if (Common.isEmpty(user)) {  
  117.                 user = "無法獲取登入使用者資訊!";  
  118.             }  
  119.         } catch (Exception e) {  
  120.             user = "無法獲取登入使用者資訊!";  
  121.         }  
  122.         // 當前使用者
  123.         try {  
  124.             map = getControllerMethodDescription(point);  
  125.             // 執行方法所消耗的時間
  126.             start = System.currentTimeMillis();  
  127.             result = point.proceed();  
  128.             end = System.currentTimeMillis();  
  129.             time = end - start;  
  130.         } catch (Throwable e) {  
  131.             thrownew RuntimeException(e);  
  132.         }  
  133.         try {  
  134.             logForm.put("accountName", user);  
  135.             logForm.put("module", map.get("module"));  
  136.             logForm.put("methods", map.get("methods"));  
  137.             logForm.put("type", map.get("type"));  
  138.             logForm.put("description", map.get("description"));  
  139.             logForm.put("actionTime", time.toString());  
  140.             logForm.put("userIP", ip);  
  141.             logMapper.addEntity(logForm);  
  142.             // *========控制檯輸出=========*//
  143.             System.out.println("=====通知開始=====");  
  144.             System.out.println("請求方法:" + className + "." + methodName + "()");  
  145.             System.out.println("方法描述:" + map);  
  146.             System.out.println("請求IP:" + ip);  
  147.             System.out.println("=====通知結束=====");  
  148.         } catch (Exception e) {  
  149.             // 記錄本地異常日誌
  150.             logger.error("====通知異常====");  
  151.             logger.error("異常資訊:{}", e.getMessage());  
  152.         }  
  153.         return result;  
  154.     }  
  155.     /** 
  156.      * 獲取註解中對方法的描述資訊 用於Controller層註解 
  157.      * 
  158.      * @param joinPoint 
  159.      *            切點 
  160.      * @return 方法描述 
  161.      * @throws Exception 
  162.      */
  163.     @SuppressWarnings("rawtypes")  
  164.     public Map<String, Object> getControllerMethodDescription(  
  165.             JoinPoint joinPoint) throws Exception {  
  166.         Map<String, Object> map = new HashMap<String, Object>();  
  167.         String targetName = joinPoint.getTarget().getClass().getName();  
  168.         String methodName = joinPoint.getSignature().getName();  
  169.         Object[] arguments = joinPoint.getArgs();  
  170.         Class targetClass = Class.forName(targetName);  
  171.         Method[] methods = targetClass.getMethods();  
  172.         for (Method method : methods) {  
  173.             if (method.getName().equals(methodName)) {  
  174.                 Class[] clazzs = method.getParameterTypes();  
  175.                 if (clazzs.length == arguments.length) {  
  176.                     map.put("module", method.getAnnotation(SystemLog.class)  
  177.                             .module());  
  178.                     map.put("methods", method.getAnnotation(SystemLog.class)  
  179.                             .methods());  
  180.                     map.put("type", method.getAnnotation(SystemLog.class)  
  181.                             .type());  
  182.                     String de = method.getAnnotation(SystemLog.class)  
  183.                             .description();  
  184.                     if (Common.isEmpty(de))  
  185.                         de = "執行成功!";  
  186.                     map.put("description", de);  
  187.                     break;  
  188.                 }  
  189.             }  
  190.         }  
  191.         return map;  
  192.     }  
  193.     <span style="color:#ff0000;">@Override
  194.     publicint getOrder() {  
  195.         // TODO Auto-generated method stub
  196.         return1;  
  197.     }</span>  
  198. }  
當執行正常時,走@Around;當執行異常時,走@AfterThrowing。結果發現,執行異常時,@AfterThrowing方法正常執行完畢,但是異常日誌並沒有插入資料表中,插入日誌的程式碼也沒報任何錯誤,遂百度之(http://my.oschina.net/HuifengWang/blog/304188),發現問題所在:

Spring中的事務是通過aop來實現的,當我們自己寫aop攔截的時候,會遇到跟spring的事務aop執行的先後順序問題,比如說動態切換資料來源的問題,如果事務在前,資料來源切換在後,會導致資料來源切換失效,所以就用到了Order(排序)這個關鍵字.我們可以通過在@AspectJ的方法中實現org.springframework.core.Ordered 這個介面來定義order的順序,order 的值越小,說明越先被執行。

當實現Ordered 介面之後,我們自己寫的aop在事務介入之前就執行了!