使用AOP設置日誌

在java開發中日誌的管理有不少種。我通常會使用過濾器,或者是Spring的攔截器進行日誌的處理。若是是用過濾器比較簡單,只要對全部的.do提交 進行攔截,而後獲取action的提交路徑就能夠獲取對每一個方法的調用。而後進行日誌記錄。使用過濾器的好處是能夠本身選擇性的對某一些方法進行過濾,記 錄日誌。可是實現起來有點麻煩。

另一種就是使用Spring的AOP了。這種方式實現起來很是簡單,只要配置一下配置文件就能夠了。但是這種方式會攔截下全部的對action的 每一個操做。使得效率比較低。不過想作詳細日誌這個方法仍是很是好的。下面我就介紹一下使用Spring AOP進行日誌記錄的方式。 html

第一種。Spring AOP對普通類的攔截操做 java

首先咱們要寫一個普通類,此類做爲日誌記錄類。 好比 spring

  1. package chen.hui.log  
  2.   
  3. public classs MyLog{  
  4.        //在類裏面寫方法,方法名詩能夠任意的。此處我用標準的before和after來表示  
  5.       public void before(){  
  6.                 System.out.println("被攔截方法調用以前調用此方法,輸出此語句");  
  7.       }  
  8.       public void after(){  
  9.                   System.out.println("被攔截方法調用以後調用此方法,輸出此語句");  
  10.       }  
  11. }  


其次咱們在寫一個類做爲被攔截類(Spring的AOP就是攔截這個類裏面的方法) express

  1. package chen.hui.log  
  2.   
  3. public class Test{//此類中方法能夠寫任意多個。我只寫一個  
  4.           public void test(){  
  5.                 Sytem.out.println("測試類的test方法被調用");  
  6.           }  
  7. }  

最後進行配置文件的編寫。在Spring的配置文件中咱們須要進行幾句話的配置 數組

  1. <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--將日誌類注入到bean中。-->  
  2. <aop:config>  
  3.     <aop:aspect id="b" ref="testLog"><!--調用日誌類-->  
  4.         <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下全部的類在調用以前都會被攔截-->  
  5.         <aop:before pointcut-ref="log" method="before"/><!--在log包下面全部的類的全部方法被調用以前都調用MyLog中的before方法-->  
  6.         <aop:after pointcut-ref="log" method="after"/>><!--在log包下面全部的類的全部方法被調用以前都調用MyLog中的after方法-->  
  7.     </aop:aspect>  
  8. </aop:config>  

到此處整個程序完成,在MyLog類裏面的before和after方法添加日誌邏輯代碼就能夠完成日誌的管理。以上是對普通類的管理,若是隻想攔截某一個類。只要把倒數第二個 *  改爲類名就能夠了。 app

  第二:使用Spring AOP對action作日誌管理 測試

若是是想攔截action對action作日誌管理,基本和上面差很少,可是要注意。如下幾點 ui

首先仍是要寫一個普通類,不過此類中的方法須要傳入參數。 好比 this

  1. package chen.hui.log  
  2.   
  3. import org.aspectj.lang.JoinPoint;  
  4.   
  5. public classs MyLog{  
  6.   
  7.        //在類裏面寫方法,方法名詩能夠任意的。此處我用標準的before和after來表示  
  8.   
  9.         //此處的JoinPoint類能夠獲取,action全部的相關配置信息和request等內置對象。  
  10.   
  11.       public void before(JoinPoint joinpoint){  
  12.   
  13.                 joinpoint.getArgs();//此方法返回的是一個數組,數組中包括request以及ActionCofig等類對象  
  14.   
  15.                 System.out.println("被攔截方法調用以前調用此方法,輸出此語句");  
  16.       }  
  17.       public void after(JoinPoint joinpoint){  
  18.   
  19.                   System.out.println("被攔截方法調用以後調用此方法,輸出此語句");  
  20.       }  
  21. }  

其次咱們在寫一個action類做爲被攔截類(Spring的AOP就是攔截這個類裏面的方法) spa

  1. package chen.hui.log  
  2.   
  3. public class LoginAction{//此類中方法能夠寫任意多個。我只寫一個  
  4.     public void test(){  
  5.         Sytem.out.println("測試類的test方法被調用");  
  6.     }  
  7. }  

最後進行配置文件的編寫。在Spring的配置文件中咱們須要進行幾句話的配置

  1. <bean id="testLog" class="chen.hui.log.MyLog"></bean> <!--將日誌類注入到bean中。-->  
  2.       <aop:config>  
  3.             <aop:aspect id="b" ref="testLog"><!--調用日誌類-->  
  4.             <aop:pointcut id="log" expression="execution(* chen.hui.log.*.*(..))"/><!--配置在log包下全部的類在調用以前都會被攔截-->  
  5.             <aop:before pointcut-ref="log" method="before"/><!--在log包下面全部的類的全部方法被調用以前都調用MyLog中的before方法-->  
  6.             <aop:after pointcut-ref="log" method="after"/><!--在log包下面全部的類的全部方法被調用以前都調用MyLog中的after方法-->  
  7.       </aop:aspect>  
  8.  </aop:config>  

除了參數外其餘地方基本和普通類類似。

須要注意的是:普通類能夠監控單一的類,而action在配置文件中只能到包名而不能到action的類名。否則會報錯。就是說若是要記錄日誌就要記錄全部的action而不能記錄其中一個,這是我試了很久得出的結果。



前幾天作項目時,在作系統日誌這一塊,都是在每一個方法裏手寫代碼來添加,以爲很繁瑣,考慮到spring有aop的功能,便尋思着用AOP來作這個日誌功能。

首先須要傳入日誌記錄的具體操做名稱,咱們能夠用java的註解功能來帶入參數,代碼以下:

 

Java代碼   收藏代碼
  1. /** 
  2.  * 類的方法描述註解 
  3.  * @author LuoYu 
  4.  */  
  5. @Target (ElementType.METHOD)  
  6. @Retention(RetentionPolicy.RUNTIME)  
  7. @Documented  
  8. @Inherited  
  9. public @interface Log {  
  10.   
  11.     /** 要執行的操做類型好比:add操做 **/  
  12.     public String operationType() default "";  
  13.      
  14.     /** 要執行的具體操做好比:【添加倉庫】 **/  
  15.     public String operationName() default "";  
  16.      
  17. }  

 

 註解類編寫好以後,就要考慮spring我切面的問題目了,首先咱們要建立一個切點,也就是須要插入的代碼塊,代碼以下:

Java代碼   收藏代碼
  1. /** 
  2.  * 經過Spring AOP來添加系統日誌 
  3.  * @author LuoYu 
  4.  */  
  5. public class LogAspect extends BaseAction{  
  6.   
  7.     private static final long serialVersionUID = -5063868902693772455L;  
  8.   
  9.     private Log logger = LogFactory.getLog(LogAspect.class);  
  10.      
  11.     @SuppressWarnings( { "rawtypes""unchecked" } )  
  12.     public void doSystemLog(JoinPoint point) throws Throwable {   
  13.         Object[] param = point.getArgs();  
  14.         Method method = null;  
  15.         String methodName = point.getSignature().getName();   
  16.         if (!(methodName.startsWith("set") || methodName.startsWith("get")||methodName.startsWith("query"))){  
  17.             Class targetClass = point.getTarget().getClass();   
  18.             method = targetClass.getMethod(methodName, param[0].getClass());  
  19.             if (method != null) {  
  20.                 boolean hasAnnotation = method.isAnnotationPresent(com.tlj.pcxt.common.logaop.Log.class);   
  21.                 if (hasAnnotation) {  
  22.                     com.tlj.pcxt.common.logaop.Log annotation = method.getAnnotation(com.tlj.pcxt.common.logaop.Log.class);   
  23.                     String methodDescp = annotation.operationType()+annotation.operationName();  
  24.                     if (logger.isDebugEnabled()) {   
  25.                         logger.debug("Action method:" + method.getName() + " Description:" + methodDescp);   
  26.                     }   
  27.                     User appUser=(User) this.getHttpServletRequest().getSession().getAttribute("user");  
  28.                     if(appUser!=null){   
  29.                         try{   
  30.                             com.tlj.pcxt.entity.admin.Log logInfo=new com.tlj.pcxt.entity.admin.Log();   
  31.                             logInfo.setIp(this.getHttpServletRequest().getRemoteAddr());  
  32.                             logInfo.setSubmitUser(appUser);  
  33.                             logInfo.setContent(annotation.operationType()+","+appUser.getUserName()+  
  34.                                     "執行【"+annotation.operationName()+"】操做,影響數據的ID集合爲["+getID(param[0])+"]");  
  35.                             this.logService.save(logInfo);   
  36.                         }catch(Exception ex){   
  37.                             logger.error(ex.getMessage());   
  38.                         }   
  39.                     }   
  40.                 }   
  41.             }   
  42.         }   
  43.     }  
  44.      
  45.     /** 
  46.      * 經過java反射來從傳入的參數object裏取出咱們須要記錄的id,name等屬性, 
  47.      * 此處我取出的是id 
  48.      *@author 羅宇 
  49.      *@date 2013-4-11 
  50.      *@param obj 
  51.      *@return 
  52.      *@return String 
  53.      */  
  54.     public String getID(Object obj){  
  55.         if(obj instanceof String){  
  56.             return obj.toString();  
  57.         }  
  58.         PropertyDescriptor pd = null;  
  59.         Method method = null;  
  60.         String v = "";  
  61.         try{  
  62.             pd = new PropertyDescriptor("id", obj.getClass());  
  63.             method = pd.getReadMethod();   
  64.             v = String.valueOf(method.invoke(obj));  
  65.         }catch (Exception e) {  
  66.             e.printStackTrace();  
  67.         }  
  68.         return v;  
  69.     }  
  70. }  

 

 切入代碼編寫好以後,須要在applicatioContext.xml裏配置切入規則,也就是說要在哪些方法執行的時候來切入上面編寫的代碼:配置如 下:

Xml代碼   收藏代碼
  1. <aop:aspectj-autoproxy/>  
  2.     <bean id="logAspect" class="com.tlj.pcxt.common.logaop.LogAspect"/>     
  3.      <aop:config>   
  4.         <aop:aspect ref="logAspect">   
  5.             <aop:pointcut id="logPointCut" expression="  
  6.                    (execution(* com.tlj.pcxt.service.*.*Impl.add*(..)))  
  7.                 or (execution(* com.tlj.pcxt.service.*.*Impl.update*(..)))  
  8.                 or (execution(* com.tlj.pcxt.service.*.*Impl.delete*(..)))  
  9.             "/>   
  10.             <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>   
  11.         </aop:aspect>   
  12.     </aop:config>   

 

在此我配置的時在方法執行以後插入代碼塊

 

Xml代碼   收藏代碼
  1. <aop:after pointcut-ref="logPointCut" method="doSystemLog"/>  

 

 

而且是在全部以add,update,delete開頭的方法才執行,其他的方法將再也不匹配。

調用方法以下,

 

 

Java代碼   收藏代碼
  1. @Log(operationType="add操做:",operationName="添加倉庫房間")  
  2.   public void addWareHouseRoom(WareHouseRoom wareHouseRoom) throws ServiceException {  
  3.       try{  
  4.           this.getWareHouseRoomDao().save(wareHouseRoom);  
  5.       }catch (Exception e) {  
  6.           throw new ServiceException(e);  
  7.       }  
  8.   }  

 

 

 

是在方法頭前添加上面自定義的@Log註解,傳入相關日誌信息

另外,在LogAspect的doSystemLog方法裏的

Java代碼   收藏代碼
  1. Object[] param = point.getArgs();  

   就是取出所匹配方法傳入的參數,咱們記錄日誌所須要的相關參數就是從這個對象裏取出來的,而且在該方法下面的代碼會檢查所匹配的方法是否有註解@log,若是沒有,會直接跳出該方法,不作任何處理.

相關文章
相關標籤/搜索