@AspectJ使用Annotation作为方法参数的类级别注释建议

如何将注释作为为类级别注释定义的建议的参数传递? 可能吗?

从这里的post我能够获得标识所有类中由特定注释标记的公共方法的切入点。 我也可以获得建议。 但是,在上面的例子中,我不知道如何将注释变量作为参数传递。

对于方法级注释,我能够获得切入点和建议,我可以将注释作为参数传递,但我不知道如何为类级注释实现相同的注释。

下面的代码有效,但是我需要将注释作为下面程序中“ LogExecutionTimeByClass ”建议的参数,我无法获得相应的建议或切入点。

注解:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface LogExecutionTime { String level(); } 

方面:

 import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogTimeAspect { /* * Pointcut to match all the public methods. */ @Pointcut("execution(public * *(..))") public void publicMethod() {} /* * Advice for the public methods that are marked with Annotation "LogExecutionTime" and it works as expected no issue. */ @Around("publicMethod() && @annotation(annotation) ") public Object LogExecutionTimeByMethod(final ProceedingJoinPoint joinPoint,final LogExecutionTime annotation) throws Throwable { System.out.println("Invoking the method " +joinPoint.getSignature() +" by LogExecutionTimeByMethod Advice"); return joinPoint.proceed(); } /* * Pointcut to match all the public methods that are defined under the Class marked with Annotation LogExecutionTime. */ @Pointcut("within(@LogExecutionTime *)") public void beanAnnotatedWithMonitor() {} @Pointcut("publicMethod() && beanAnnotatedWithMonitor()") public void publicMethodInsideAClassMarkedWithAtMonitor() {} /* * Below Advice works but I need the LogExecutionTime annotation as an argument to below method. (similar to the advice "LogExecutionTimeByMethod" * defined above) */ @Around("publicMethodInsideAClassMarkedWithAtMonitor()") public Object LogExecutionTimeByClass(final ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Invoking the method " +joinPoint.getSignature() +" by LogExecutionTimeByClass Advice"); //System.out.println("Invoked by " + annotation.value()); //Need the Annotation Variable here as well... return joinPoint.proceed(); } /* */ } 

注释类:

 @LogExecutionTime(level="Class_Level_Invocation") public class Operator { @LogExecutionTime(level="Method_Level_Invocation") public void operate() throws InterruptedException { Thread.sleep(1000); } public void operate1() throws InterruptedException { Thread.sleep(1000); } } 

主程序:

 public class AspectJMain { public static void main(String[] args) throws InterruptedException { Operator op = new Operator(); op.operate(); op.operate1(); } } 

输出:

 Invoking the method void Operator.operate() by LogExecutionTimeByMethod Advice Invoking the method void Operator.operate() by LogExecutionTimeByClass Advice Invoking the method void Operator.operate1() by LogExecutionTimeByClass Advice 

请注意,使用Spring不是一种选择。 我必须使用AspectJ编译器。 我编译了我的类并将它们打包为jar并使用ApsectJ编译器使用下面的命令编织方面。

ajc -inpath core.jar -outjar .. \ lib \ core_woven.jar -1.5

任何指针都会有所帮助。

解决方案实际上非常简单。 我正在用原生的AspectJ风格编写代码,为了清晰起见,我更喜欢它。 您可以轻松地将其调整为@AspectJ注释样式:

 public aspect LogTimeAspect { pointcut publicMethod() : execution(public * *(..)); before(LogExecutionTime logAnn) : publicMethod() && @annotation(logAnn) { System.out.println(thisJoinPointStaticPart + " -> " + logAnn.level()); } before(LogExecutionTime logAnn) : publicMethod() && @within(logAnn) { System.out.println(thisJoinPointStaticPart + " -> " + logAnn.level()); } } 

输出如下:

 execution(void Operator.operate()) -> Method_Level_Invocation execution(void Operator.operate()) -> Class_Level_Invocation execution(void Operator.operate1()) -> Class_Level_Invocation 

如你看到的,

  • 除非你想操纵任何参数或阻止捕获的方法执行,否则不需要around()建议, before()就足够了,
  • 如果只使用正确的语法,可以通过@annotation()@within()将注释绑定到命名参数。

请享用! :-)


更新:为方便起见,这是方面的@AspectJ版本,因为您似乎在使用本机语法调整我的解决方案时遇到问题:

 import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogTimeAspect { @Pointcut("execution(public * *(..))") public void publicMethod() {} @Around("publicMethod() && @annotation(logAnn)") public Object LogExecutionTimeByMethod(ProceedingJoinPoint joinPoint, LogExecutionTime logAnn) throws Throwable { System.out.println(joinPoint + " -> " + logAnn.level()); return joinPoint.proceed(); } @Around("publicMethod() && @within(logAnn)") public Object LogExecutionTimeByClass(ProceedingJoinPoint joinPoint, LogExecutionTime logAnn) throws Throwable { System.out.println(joinPoint + " -> " + logAnn.level()); return joinPoint.proceed(); } } 

结果将与我的原始版本相同。