@AspectJ pointcut для всех методов класса с определенной аннотацией - PullRequest
113 голосов
/ 06 января 2010

Я хочу отслеживать все открытые методы всех Классов с указанной аннотацией (скажем, @Monitor) (примечание: аннотация находится на уровне класса). Что может быть возможным pointcut для этого? Примечание. Я использую Spring AOP в стиле @AspectJ.

Ответы [ 9 ]

149 голосов
/ 26 марта 2010

Вы должны комбинировать тип pointcut с методом pointcut.

Эти pointcuts выполнят работу по поиску всех открытых методов внутри класса, помеченного аннотацией @Monitor:

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

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

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

Посоветуйте последний pointcut, который объединяет первые два, и все готово!

Если вам интересно, я написал шпаргалку со стилем @AspectJ здесь с соответствующим примером документа здесь.

54 голосов
/ 15 мая 2012

Использование аннотаций, как описано в вопросе.

Аннотация: @Monitor

Аннотация по классу, app/PagesController.java:

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

Аннотация к методу, app/PagesController.java:

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

Пользовательская аннотация, app/Monitor.java:

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

Аспект для аннотации, 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());
    }
}

Включить AspectJ, servlet-context.xml:

<aop:aspectj-autoproxy />

Включить библиотеки AspectJ, pom.xml:

<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
12 голосов
/ 06 января 2010

Примерно так:

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

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

6 голосов
/ 25 июня 2017

Использование

@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
    public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
3 голосов
/ 01 июля 2013

должно быть достаточно, чтобы пометить ваш метод аспекта следующим образом:

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

посмотрите на this для пошагового руководства по этому вопросу.

3 голосов
/ 12 января 2011

Вы также можете определить pointcut как

public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
2 голосов
/ 24 июня 2011

Самый простой способ выглядит так:

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

   return pjp.proceed();

   // perform actions after
}

Он будет перехватывать выполнение всех методов, специально помеченных как '@MyHandling' в классе 'YourService'. Чтобы перехватить все методы без исключения, просто поместите аннотацию непосредственно в класс.

Независимо от приватной / публичной области видимости, но имейте в виду, что spring-aop не может использовать аспект для вызовов методов в одном и том же экземпляре (обычно приватных), потому что в этом случае он не использует прокси-класс. 1006 *

Здесь мы используем @Around advice, но в основном это тот же синтаксис, что и @Before, @After или любой совет.

Кстати, аннотация @MyHandling должна быть настроена так:

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

}
1 голос
/ 19 декабря 2014

С весны 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 голос
/ 23 апреля 2013

Вы можете использовать PerformanceMonitoringInterceptor Spring и программно зарегистрировать совет, используя beanpostprocessor.

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