2012-01-12 4 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 к моим методам автоматически с АОП (и байт кода аппаратуры). Я думаю о AspectJ. Имеет ли это смысл? Вы знаете какой-либо open-source, который делает именно это?

+0

Да, это имеет смысл. AspectJ является открытым исходным кодом, как и Javaassist. – Perception

ответ

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

4

Вы можете использовать различные точки, чтобы выполнить свое требование. Это documentation поможет вам.

Straight forward solution

+1

Это как другая документация. Не хрустящее решение – Dish

22

@Loggable аннотаций и аспект AspectJ из jcabi-aspects является готовый механизм для вас (я разработчик):

@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

+1

@DaveJarvis, этот конкретный код будет регистрировать только выход, log, вам понадобится '@Loggable (prepend = true)', см. http://aspects.jcabi.com/apidocs-0.22.5/com/jcabi/aspects/Loggable.html – yegor256

+0

@DaveJarvis, что на данный момент невозможно , но мы можем сделать это возможным. Пожалуйста, отправьте вопрос в наш репозиторий GitHub, и мы увидим, что мы можем сделать: https://github.com/jcabi/jcabi-aspects/issues (и спасибо за обновление ответа) – yegor256

1

Вы можете попробовать этот open source http://code.google.com/p/perfspy/. PerfSpy - это журнал выполнения, контроль производительности и проверка кода. Он использует ApsectJ, чтобы сплести код приложения во время выполнения и регистрирует время выполнения каждого метода и его входных параметров и значений. Он имеет приложение пользовательского интерфейса, в котором вы можете просматривать вызовы метода и их значения ввода и возврата в виде деревьев. С его помощью вы можете выявить узкие места в производительности и понять сложный поток кода.

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 зависимостей Compile

<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

+0

Вы сделали и сделали чистую сборку? –

+0

Почему вы написали код для совета самостоятельно, пока вы также используете библиотеку? – Dish

Смежные вопросы