2012-01-12 8 views
21

me gustaría añadir mensajes de "rastrear" a todos mis métodos públicos de la siguiente manera:¿Cómo se usa AOP con AspectJ para el inicio de sesión?

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

Ahora me gustaría añadir todos aquellos log.trace a mis métodos de forma automática con AOP (y la instrumentación de código de bytes). Estoy pensando en AspectJ. ¿Tiene sentido? ¿Conoces alguna fuente abierta, que hace exactamente eso?

+0

Sí, tiene sentido. AspectJ es de código abierto, al igual que Javaassist. – Perception

Respuesta

23

He creado un aspecto sencillo para capturar la ejecución de los métodos públicos. El núcleo de este código AspectJ es la definición pointcut:

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

Aquí estamos capturando todos los métodos públicos con cualquier tipo de retorno, en cualquier paquete y cualquier clase, con cualquier número de parámetros.

La ejecución asesoramiento puede ser visualizado en el siguiente fragmento de código:

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

Este consejo uso thisJoinPoint para obtener la firma del método y los argumentos. Y eso es. Aquí está el código aspecto:

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

Para ejemplos más complejos que recomendaría el libro AspectJ: In Action.

+3

Tenga cuidado con el 'System.out', realmente debería usar una fachada de marco de registro como SLF4J – jediz

4

Puede usar diferentes puntos de corte para hacer su requerimiento. Este documentation te ayudará.

recta forward solution

+1

Esto es como otra documentación. No es una solución nítida – Dish

22

@Loggable anotación y un aspecto AspectJ de jcabi-aspects es un mecanismo listo para usted (yo soy un desarrollador):

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

Para conectarse tanto a la entrada y salida, según los requisitos de la pregunta:

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

Todos los registros van a SLF4J. Consulte this post para obtener más detalles.

+0

@DaveJarvis sí, esta biblioteca registra ambos _and_ saliendo de – yegor256

+1

@DaveJarvis este código en particular solo registrará la salida, a log ambos necesitarán '@Loggable (prepend = true)', vea http://aspects.jcabi.com/apidocs-0.22.5/com/jcabi/aspects/Loggable.html – yegor256

+0

@DaveJarvis que no es posible en este momento , pero podemos hacerlo posible. Envíe un problema a nuestro repositorio de GitHub y veremos qué podemos hacer: https://github.com/jcabi/jcabi-aspects/issues (y gracias por actualizar la respuesta) – yegor256

1

Puede probar esta fuente abierta http://code.google.com/p/perfspy/. PerfSpy es una herramienta de registro de tiempo de ejecución, monitoreo de rendimiento e inspección de código. Utiliza ApsectJ para tejer alrededor del código de su aplicación en tiempo de ejecución, y registra el tiempo de ejecución de cada método y sus parámetros y valores de entrada. Tiene una aplicación de interfaz de usuario, en la que puede ver las invocaciones de métodos y sus valores de entrada y retorno como árboles. Con él, puede detectar cuellos de botella de rendimiento y comprender el flujo de código complejo.

0

Aquí es mi sencilla aplicación para registrar entrar, salir y excepciones a los métodos

anotación

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 { 

} 

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

    } 
} 

Como Usar

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

dependencias Maven Compilar

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

Tejiendo

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

Utilicé su código y proyecto exactos configuración, pero el interceptor nunca se llama. ¿Alguna ayuda? – jre247

+0

has hecho y limpia la construcción? –

+0

¿Por qué ha escrito usted mismo el código para obtener consejos mientras también usa la biblioteca? – Dish

Cuestiones relacionadas