2013-07-05 2 views
5

Как я могу получить аннотацию, которая будет передана в качестве аргумента для рекомендации, определенной для аннотации на уровне класса? Является ли это возможным?@AspectJ Класс уровня Аннотация Совет с аннотацией как аргумент метода

Из сообщения here Я могу получить точку, которая идентифицирует все общедоступные методы в классе, которые отмечены определенной аннотацией. Я также могу получить совет. Однако я не знаю, как получить переменную аннотации, переданную как аргумент в приведенном выше случае.

Для аннотации уровня метода я могу получить pointcut и советы, в которых я могу получить аннотацию, переданную как аргумент, но я не знаю, как добиться того же для аннотации на уровне класса.

Ниже код работает, но мне нужно, чтобы получить аннотацию в качестве аргумента за советы «LogExecutionTimeByClass» в программе ниже, и я не мог в состоянии получить соответствующую консультацию или Pointcut то же самое.

Аннотация:

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

/* 
    */ 
} 

Annotated Класс:

@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. Я скомпилировал свои классы и упаковал их как банку и использовал компилятор ApsectJ, чтобы сплести аспект, используя команду ниже.

AJC -inpath core.jar -outjar .. \ Lib \ core_woven.jar -1,5

Любой указатель будет полезно.

ответ

12

Решение на самом деле довольно простое. Я пишу свой код в родном стиле 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() advice, before() достаточно, если вы не хотите манипулировать любыми параметрами или блокировать выполнение захваченных методов,
  • вы можете связать аннотации, о которых идет речь, с помощью @annotation() или @within() с именованными параметрами, если вы просто используете правильный синтаксис.

Наслаждайтесь!:-)


Update: Вот версия @ 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(); 
    } 
} 

Результаты будут идентичный моей оригинальной версии.

+0

Спасибо. Позвольте мне попробовать. Причиной для Around является получение времени выполнения метода. – param83

+0

Я попытался, но не смог передать аргумент аннотации через внутри, но ниже точечные работы @Pointcut ("publicMethod() && beanAnnotatedWithMonitor() && @annotation (аннотация)") – param83

+0

Вам действительно не нужно beanAnnotatedWithMonitor() ', см. мое обновление выше. – kriegaex