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

时间:2013-07-05 04:40:54

标签: java aspectj

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

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

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

以下代码有效,但我需要在下面的程序中将注释作为建议“ 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

任何指针都会有所帮助。

1 个答案:

答案 0 :(得分:14)

解决方案实际上非常简单。我用原生的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();
    }
}

结果与原始版本相同。