2012-01-12 92 views
21

我想添加如下「跟蹤」消息,我所有的公共方法:如何使用AOP與AspectJ進行日誌記錄?

public void foo(s:String, n:int) { // log is a log4j logger or any other library 
    log.trace(String.format("Enter foo with s: %s, n: %d", s, n)) 
    ... 
    log.trace("Exit foo") 
}

現在我想所有這些log.trace與AOP(和字節代碼裝備),自動添加到我的方法。我正在考慮AspectJ。是否有意義?你知道任何開源軟件嗎?

+0

是的,這是有道理的。 AspectJ是開源的,就像Javaassist一樣。 – Perception 2012-01-12 17:06:23

回答

23

我創建了一個簡單的方面來捕捉的公共方法的執行。這樣的AspectJ代碼的核心是切入點定義:

pointcut publicMethodExecuted(): execution(public * *(..)); 

在這裏,我們擷取與任何返回類型的所有公共方法,在任何包裝和任何階級,任何數量的參數。

意見執行可能下面的代碼片段進行可視化:

after(): publicMethodExecuted() { 
    System.out.printf("Enters on method: %s. \n", thisJoinPoint.getSignature()); 

    Object[] arguments = thisJoinPoint.getArgs(); 
    for (int i =0; i < arguments.length; i++){ 
     Object argument = arguments[i]; 
     if (argument != null){ 
      System.out.printf("With argument of type %s and value %s. \n", argument.getClass().toString(), argument); 
     } 
    } 

    System.out.printf("Exits method: %s. \n", thisJoinPoint.getSignature()); 
} 

這個建議使用thisJoinPoint獲得方法簽名和參數。就是這樣。以下是方面代碼:

public aspect LogAspect { 

pointcut publicMethodExecuted(): execution(public * *(..)); 

after(): publicMethodExecuted() { 
    System.out.printf("Enters on method: %s. \n", thisJoinPoint.getSignature()); 

    Object[] arguments = thisJoinPoint.getArgs(); 
    for (int i =0; i < arguments.length; i++){ 
     Object argument = arguments[i]; 
     if (argument != null){ 
      System.out.printf("With argument of type %s and value %s. \n", argument.getClass().toString(), argument); 
     } 
    } 
    System.out.printf("Exits method: %s. \n", thisJoinPoint.getSignature()); 
} 

對於更復雜的例子我會推薦這本書AspectJ: In Action

+3

小心'System.out',你真的應該使用日誌框架外觀,如SLF4J – jediz 2017-01-06 10:28:59

4

您可以使用不同的切入點來滿足您的要求。這documentation將幫助你。

forward solution

+1

這就像另一個文檔。不是一個明智的解決方案 – Dish 2017-02-02 11:28:27

22

@Loggable註釋和jcabi-aspects一個AspectJ方面對你是一個現成的機制,(我是一個開發者):

@Loggable(Loggable.DEBUG) 
public String load(URL url) { 
    return url.openConnection().getContent(); 
} 

要登錄進入和退出,按照問題的要求:

@Loggable(Loggable.DEBUG, prepend=true) 
public String load(URL url) { 
    return url.openConnection().getContent(); 
} 

所有日誌都轉到SLF4J。檢查this post瞭解更多詳情。

+0

@DaveJarvis是的,這個庫記錄輸入和退出 – yegor256 2016-07-17 22:44:29

+1

@DaveJarvis這個特定的代碼只會記錄退出,到記錄你將需要'@Loggable(prepend = true)',請參閱http://aspects.jcabi.com/apidocs-0.22.5/com/jcabi/aspects/Loggable.html – yegor256 2016-07-18 05:52:03

+0

@DaveJarvis目前不可能,但我們可以做到這一點。請提交一個問題到我們的GitHub倉庫,我們將看到我們可以做什麼:https://github.com/jcabi/jcabi-aspects/issues(謝謝你更新答案) – yegor256 2016-07-19 01:13:59

1

你可以試試這個開源碼http://code.google.com/p/perfspy/。 PerfSpy是一個運行時日誌記錄,性能監視和代碼檢查工具。它使用ApsectJ在運行時編譯應用程序代碼,並記錄每個方法及其輸入參數和值的執行時間。它有一個UI應用程序,您可以在其中查看方法調用及其輸入和返回值作爲樹。有了它,您可以發現性能瓶頸並瞭解複雜的代碼流。

0

這是我簡單的實現登錄進入,退出和日誌方法

註釋

package test; 

import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.METHOD, ElementType.TYPE }) 
public @interface Audit { 

} 

例外攔截

import java.lang.reflect.Method; 
import java.util.Arrays; 
import java.util.logging.Level; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.reflect.MethodSignature; 


@Aspect 
public class ExceptionInterceptor { 

    private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(ExceptionInterceptor.class.getName()); 

    @Around("execution(* * (..))" 
      + " && @annotation(test.Audit)" 
    ) 
    public Object intercept(final ProceedingJoinPoint point) throws Throwable { 
     final Method method 
       = MethodSignature.class.cast(point.getSignature()).getMethod(); 
     String mName = method.getName(); 
     String cName = method.getDeclaringClass().getSimpleName(); 
     LOGGER.log(Level.INFO, "Entering {0}:{1}", new Object[]{cName, mName}); 
     Object out = null; 
     try { 
      out = point.proceed(); 
     } catch (Throwable t) { 
      logExceptions(t, point); 
     } 
     LOGGER.log(Level.INFO, "Exiting {0}:{1}", new Object[]{cName, mName}); 
     return out; 
    } 

    private void logExceptions(Throwable t, final ProceedingJoinPoint point) { 
     final Method method 
       = MethodSignature.class.cast(point.getSignature()).getMethod(); 
     String mName = method.getName(); 
     String cName = method.getDeclaringClass().getSimpleName(); 
     Object[] params = point.getArgs(); 
     StringBuilder sb = new StringBuilder(); 
     sb.append("Exception caught for ["); 
     sb.append(cName); 
     sb.append("."); 
     sb.append(mName); 
     for (int i = 0; i < params.length; i++) { 
      Object param = params[i]; 

      sb.append("\n"); 
      sb.append(" [Arg=").append(i); 
      if (param != null) { 
       String type = param.getClass().getSimpleName(); 

       sb.append(", ").append(type); 

       // Handle Object Array (Policy Override) 
       if (param instanceof Object[]) { 
        sb.append("=").append(Arrays.toString((Object[]) param)); 
       } else { 
        sb.append("=").append(param.toString()); 
       } 
      } else { 
       sb.append(", null"); 
      } 
      sb.append("]"); 
      sb.append("\n"); 
     } 
     LOGGER.log(Level.SEVERE, sb.toString(), t); 

    } 
} 

如何使用它

@Audit 
public void testMethod(Int a,int b, String c){ 
} 

Maven依賴 編譯

<dependency> 
     <groupId>org.aspectj</groupId> 
     <artifactId>aspectjrt</artifactId> 
     <version>1.8.7</version> 
    </dependency> 

編織

 <plugin> 
      <groupId>com.jcabi</groupId> 
      <artifactId>jcabi-maven-plugin</artifactId> 
      <executions> 
       <execution> 
        <phase>compile</phase> 
        <goals> 
         <goal>ajc</goal> 
        </goals> 
       </execution> 
      </executions> 
     </plugin> 
+0

我用你的確切代碼和項目設置,但攔截器永遠不會被調用。任何幫助? – jre247 2016-12-21 14:37:29

+0

你做完了,乾淨的構建? – 2016-12-21 17:54:20

+0

爲什麼在你使用圖書館的時候你自己寫了一些建議的代碼? – Dish 2017-02-02 11:19:35