如何使用AOP和AspectJ进行日志记录?

我想在我的所有公共方法中添加“trace”消息,如下所示:

  public void foo(s:String,n:int){// log是一个log4j记录器或任何其他库
   log.trace(String.format(“输入foo with s:%s,n:%d”,s,n))
   ...
   log.trace(“退出foo”) 
 } 

现在我想用AOP(和字节码检测)自动将所有log.trace添加到我的方法中。 我正在考虑AspectJ 。 是否有意义? 你知道任何开源的吗?

我创建了一个简单的方面来捕获公共方法的执行。 这个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 。

来自jcabi-aspects的 @Loggable注释和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。 查看此post了解更多详情。

您可以使用不同的切入点来满足您的要求。 本文档将为您提供帮助。

直截了当的解决方案

您可以试用这个开源http://code.google.com/p/perfspy/ 。 PerfSpy是一个运行时日志,性能监视和代码检查工具。 它使用ApsectJ在运行时编织应用程序代码,并记录每个方法的执行时间及其输入参数和值。 它有一个UI应用程序,您可以在其中查看方法调用及其输入并将值作为树返回。 有了它,您可以发现性能瓶颈并理解复杂的代码流。

这是我记录输入,退出和记录方法exception的简单实现

注解

 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依赖项编译

   org.aspectj aspectjrt 1.8.7  

织造

   com.jcabi jcabi-maven-plugin   compile  ajc