2012-01-12 13 views
21

Chciałbym dodać komunikaty „Śledzenie” do wszystkich moich metod publicznych, co następuje:Jak używać AOP z AspectJ do rejestrowania?

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") 
}

Teraz chciałbym dodać tych wszystkich log.trace do moich metod automatycznie z AOP (i kodu bajtowego oprzyrządowania). Myślę o AspectJ. Czy jest sens? Czy znasz jakieś open-source, które dokładnie to robi?

+0

Tak, to ma sens. AspectJ jest open source, podobnie jak Javaassist. – Perception

Odpowiedz

23

Stworzyłem prosty aspekt uchwycić wykonanie metod publicznych. Rdzeniem tego kodu AspectJ jest definicja punktu przekroju:

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

Tutaj jesteśmy przechwytywania wszystkie metody publiczne z każdego rodzaju powrót, na każdym opakowaniu i dowolnej klasy, z dowolną liczbą parametrów.

Wykonanie rada może być wizualizowane na fragmencie kodu poniżej:

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()); 
} 

Ta rada Użyj thisJoinPoint uzyskać podpis metody i argumenty. I to wszystko. Oto kod aspekt: ​​

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()); 
} 

Dla bardziej złożonych przykładów Polecam książkę AspectJ: In Action.

+3

Strzeż się 'System.out', powinieneś używać elewacji struktury logowania, takiej jak SLF4J – jediz

22

@Loggable adnotacji i aspekt AspectJ z jcabi-aspects jest gotowy mechanizm ciebie (jestem programistą):

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

do zalogowania zarówno wejście i wyjście, zgodnie z wymogami pytaniem jest:

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

Wszystkie dzienniki są przesyłane do SLF4J. Aby uzyskać więcej informacji, sprawdź numer this post.

+0

@DaveJarvis tak, ta biblioteka loguje zarówno wprowadzanie _i_ wyjmowanie – yegor256

+1

@DaveJarvis ten szczególny kod będzie rejestrował tylko wyjście, do zaloguj się, będziesz potrzebować '@Loggable (prepend = true)', zobacz http://aspects.jcabi.com/apidocs-0.22.5/com/jcabi/aspects/Loggable.html – yegor256

+0

@DaveJarvis, które nie są obecnie możliwe , ale możemy to umożliwić. Prześlij problem do repozytorium GitHub, a zobaczymy, co możemy zrobić: https://github.com/jcabi/jcabi-aspects/issues (i dzięki za aktualizację odpowiedzi) – yegor256

1

Możesz wypróbować ten open source http://code.google.com/p/perfspy/. PerfSpy to narzędzie do rejestrowania czasu pracy, monitorowania wydajności i narzędzia do kontroli kodu. Używa ApsectJ do tkania wokół kodu aplikacji w czasie wykonywania i rejestruje czas wykonania każdej metody oraz jej parametrów wejściowych i wartości. Ma aplikację interfejsu użytkownika, w której można wyświetlić wywołania metody oraz ich wartości wejściowe i wartości zwracane jako drzewa. Dzięki niemu możesz dostrzec wąskie gardła wydajności i zrozumieć złożony przepływ kodu.

0

Oto moja prosta implementacja zalogować wprowadzanie, zamykanie, a wyjątki od metod

adnotacji

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 { 

} 

zalogować Interceptor

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); 

    } 
} 

jak go używać

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

Maven zależności kompilacji

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

Weaving

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

Użyłem twojego dokładnego kodu i projektu konfiguracji, ale przechwytywacz nigdy nie jest wywoływany. Jakaś pomoc? – jre247

+0

zrobiłeś i wyczyściłeś kompilację? –

+0

Dlaczego sam napisałeś kod, gdy korzystasz z biblioteki? – Dish

Powiązane problemy