【问题标题】:@AspectJ Class level Annotation Advice with Annotation as method argument@AspectJ 以注解作为方法参数的类级别注解建议
【发布时间】:2013-07-03 02:27:21
【问题描述】:

我怎样才能让注解作为定义的 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

任何指针都会有所帮助。

【问题讨论】:

    标签: java aop aspectj


    【解决方案1】:

    解决方案其实很简单。我正在以原生 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();
        }
    }
    

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

    【讨论】:

    • 谢谢。让我试试看。 Around的原因是为了获取方法的执行时间。
    • 我尝试过但无法通过切入点内但低于切入点的方法传递注释参数@Pointcut("publicMethod() && beanAnnotatedWithMonitor() && @annotation(annotation)")
    • 你真的不需要beanAnnotatedWithMonitor(),看我上面的更新。
    猜你喜欢
    • 1970-01-01
    • 2021-04-12
    • 2011-06-09
    • 1970-01-01
    • 2016-08-22
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多