2013-07-05 1 views
5

Come posso ottenere l'annotazione da passare come argomento per l'avviso definito per l'annotazione a livello di classe ? È possibile?@AspectJ Avviso annotazione a livello di classe con annotazione come argomento metodo

Dal post here Sono in grado di ottenere il punto di taglio che identifica tutto il metodo pubblico nella classe che è contrassegnato da una specifica annotazione. Sono in grado di ottenere il consiglio applicato pure. Tuttavia, non so come ottenere la variabile di annotazione passata come argomento nel caso precedente.

Per un'annotazione a livello di metodo, sono in grado di ottenere il punto e il consiglio in cui posso ottenere l'annotazione passata come argomento, ma non so come ottenere lo stesso per l'annotazione a livello di classe.

Il codice sotto funziona, ma ho bisogno di ottenere l'annotazione come argomento per il consiglio “LogExecutionTimeByClass” in programma qui sotto e non ho potuto in grado di ottenere consulenza o pointcut appropriata per lo stesso.

della nota:

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

Aspetto:

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 Classe:

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

programma principale:

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

uscita:

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 

Si prega di notare che l'utilizzo di primavera è non è un'opzione. Devo usare il compilatore AspectJ. Ho compilato le mie classi e le ho impacchettate come jar e ho usato il compilatore ApsectJ per tessere l'aspetto usando il comando below.

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

Qualsiasi puntatore sarebbe utile.

risposta

12

La soluzione è in realtà abbastanza semplice. Sto scrivendo il mio codice in stile AspectJ nativo, lo preferisco per chiarezza. Sarete facilmente in grado di adattarlo alle @AspectJ stile della nota:

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

L'uscita è la seguente:

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

Come si può vedere,

  • non v'è alcuna necessità di L'avviso around(), before() è sufficiente se non si desidera modificare alcun parametro o bloccare le esecuzioni del metodo acquisito,
  • è possibile eseguire il binding le annotazioni in questione tramite @annotation() o @within() ai parametri denominati se si utilizza solo la sintassi corretta.

Divertiti!:-)


Aggiornamento: ecco la versione @AspectJ dell'aspetto per la vostra comodità e perché sembrava avere problemi di adattamento mia soluzione dalla sintassi nativa:

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

I risultati saranno identico alla mia versione originale.

+0

Grazie. Fammi provare. La ragione per Around è ottenere il tempo di esecuzione del metodo. – param83

+0

Ho provato ma non sono riuscito a passare l'argomento dell'annotazione tramite all'interno ma sotto il punto di taglio works @Pointcut ("publicMethod() && beanAnnotatedWithMonitor() && @annotation (annotation)") – param83

+0

Non hai davvero bisogno di 'beanAnnotatedWithMonitor()', vedere il mio aggiornamento sopra. – kriegaex