web-dev-qa-db-fra.com

@AspectJ pointcut pour toutes les méthodes d'une classe avec une annotation spécifique

Je souhaite surveiller toutes les méthodes publiques de toutes les classes avec une annotation spécifiée (par exemple, @Monitor) (note: l'annotation est au niveau de la classe). Quel pourrait être un point possible pour cela? Remarque: J'utilise le style Spring AOP de @AspectJ.

114
Rejeev Divakaran

Vous devez combiner un type pointcut avec une méthode.

Ces raccourcis feront le travail pour trouver toutes les méthodes publiques dans une classe marquée avec une annotation @Monitor:

@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}

@Pointcut("execution(public * *(..))")
public void publicMethod() {}

@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}

Conseil le dernier point de coupe qui combine les deux premiers et vous avez terminé!

Si vous êtes intéressé, j'ai écrit un aide-mémoire avec le style @AspectJ ici avec un exemple de document ici.

151
Espen

Utiliser des annotations, comme décrit dans la question.

Annotation: @Monitor

Annotation sur la classe, app/PagesController.Java:

package app;
@Controller
@Monitor
public class PagesController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody String home() {
        return "w00t!";
    }
}

Annotation sur la méthode, app/PagesController.Java:

package app;
@Controller
public class PagesController {
    @Monitor
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody String home() {
        return "w00t!";
    }
}

Annotation personnalisée, app/Monitor.Java:

package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}

Aspect pour l'annotation, app/MonitorAspect.Java:

package app;
@Component
@Aspect
public class MonitorAspect {
    @Before(value = "@within(app.Monitor) || @annotation(app.Monitor)")
    public void before(JoinPoint joinPoint) throws Throwable {
        LogFactory.getLog(MonitorAspect.class).info("monitor.before, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
    }

    @After(value = "@within(app.Monitor) || @annotation(app.Monitor)")
    public void after(JoinPoint joinPoint) throws Throwable {
        LogFactory.getLog(MonitorAspect.class).info("monitor.after, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
    }
}

Activer AspectJ, servlet-context.xml:

<aop:aspectj-autoproxy />

Inclure les bibliothèques AspectJ, pom.xml:

<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
54
Alex

Quelque chose comme ca:

@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
    if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
       // perform the monitoring actions
    }
}

Notez que vous ne devez avoir aucun autre conseil sur la même classe avant celui-ci, car les annotations seront perdues après le remplacement du proxy.

13
Bozho

Utilisation

@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
    public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
6
Davide Consonni

Vous pouvez également définir le pointcut comme

public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
3
Shekhar

cela devrait suffire à marquer votre méthode d'aspect comme ceci:

@After("@annotation(com.marcot.CommitTransaction)")
    public void after() {

jetez un oeil à this pour un guide étape par étape à ce sujet.

3
marcocast

Le moyen le plus simple semble être:

@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
   throws Throwable {
   // perform actions before

   return pjp.proceed();

   // perform actions after
}

Il interceptera l'exécution de toutes les méthodes spécifiquement annotées avec '@MyHandling' dans la classe 'YourService'. Pour intercepter toutes les méthodes sans exception, il suffit de placer l'annotation directement sur la classe.

N'importe le domaine privé/public ici, mais gardez à l'esprit que spring-aop ne peut pas utiliser l'aspect pour les appels de méthode dans la même instance (généralement privée), car il n'utilise pas la classe proxy dans ce cas.

Nous utilisons ici les conseils @Around, mais la syntaxe est la même avec @Avant, @After ou tout autre conseil.

En passant, l'annotation @MyHandling doit être configurée comme suit:

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {

}
2
Donatello

Du printemps AnnotationTransactionAspect:

/**
 * Matches the execution of any public method in a type with the Transactional
 * annotation, or any subtype of a type with the Transactional annotation.
 */
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
    execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
1
xmedeko

Vous pouvez utiliser PerformanceMonitoringInterceptor de Spring et enregistrer par programmation les conseils à l'aide d'un processeur de haricot.

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Monitorable
{

}


public class PerformanceMonitorBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, Ordered,
    InitializingBean
{

  private Class<? extends Annotation> annotationType = Monitorable.class;

  private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

  private Advisor advisor;

  public void setBeanClassLoader(ClassLoader classLoader)
  {
    this.beanClassLoader = classLoader;
  }

  public int getOrder()
  {
    return LOWEST_PRECEDENCE;
  }

  public void afterPropertiesSet()
  {
    Pointcut pointcut = new AnnotationMatchingPointcut(this.annotationType, true);
    Advice advice = getInterceptor();
    this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
  }

  private Advice getInterceptor()
  {
    return new PerformanceMonitoringInterceptor();
  }

  public Object postProcessBeforeInitialization(Object bean, String beanName)
  {
    return bean;
  }

  public Object postProcessAfterInitialization(Object bean, String beanName)
  {
    if(bean instanceof AopInfrastructureBean)
    {
      return bean;
    }
    Class<?> targetClass = AopUtils.getTargetClass(bean);
    if(AopUtils.canApply(this.advisor, targetClass))
    {
      if(bean instanceof Advised)
      {
        ((Advised)bean).addAdvisor(this.advisor);
        return bean;
      }
      else
      {
        ProxyFactory proxyFactory = new ProxyFactory(bean);
        proxyFactory.copyFrom(this);
        proxyFactory.addAdvisor(this.advisor);
        return proxyFactory.getProxy(this.beanClassLoader);
      }
    }
    else
    {
      return bean;
    }
  }
}
1
Vikram