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

par*_*m83 5 java aspectj

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

这里的帖子我能够得到一个标点,它标识了类中由特定注释标记的所有公共方法.我也可以得到建议.但是,在上面的例子中,我不知道如何将注释变量作为参数传递.

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

下面的代码有效,但我需要将注释作为下面程序中" 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();
}
Run Code Online (Sandbox Code Playgroud)

方面:

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

/*
    */
}
Run Code Online (Sandbox Code Playgroud)

注释类:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

主程序:

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

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

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

任何指针都会有所帮助.

kri*_*aex 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

execution(void Operator.operate()) -> Method_Level_Invocation
execution(void Operator.operate()) -> Class_Level_Invocation
execution(void Operator.operate1()) -> Class_Level_Invocation
Run Code Online (Sandbox Code Playgroud)

如你看到的,

  • 除非你想操纵任何参数或阻止捕获的方法执行,否则不需要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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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