Java @AspectJ 切入点用于具有特定注释的类的所有方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2011089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:28:40  来源:igfitidea点击:

@AspectJ pointcut for all methods of a class with specific annotation

javaaopaspectjspring-aop

提问by Rejeev Divakaran

I want to monitor all public methods of all Classes with specified annotation (say @Monitor) (note: Annotation is at class level). What could be a possible pointcut for this? Note: I am using @AspectJ style Spring AOP.

我想用指定的注释(比如@Monitor)监视所有类的所有公共方法(注意:注释是在类级别)。这可能是什么切入点?注意:我使用的是@AspectJ 风格的 Spring AOP。

回答by Bozho

Something like that:

类似的东西:

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

Note that you must not have any other advice on the same class beforethis one, because the annotations will be lost after proxying.

请注意,之前,您不能对同一类有任何其他建议,因为代理后注释将丢失。

回答by Espen

You should combine a type pointcut with a method pointcut.

您应该将类​​型切入点与方法切入点结合起来。

These pointcuts will do the work to find all public methods inside a class marked with an @Monitor annotation:

这些切入点将完成在标有 @Monitor 注释的类中查找所有公共方法的工作:

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

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

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

Advice the last pointcut that combines the first two and you're done!

建议结合前两个的最后一个切入点,你就完成了!

If you're interested, I have written a cheat sheetwith @AspectJ style here with a corresponding example documenthere.

如果你有兴趣,我在这里写了一个带有@AspectJ 风格的备忘单,这里有一个相应的示例文档

回答by Shekhar

You can also define the pointcut as

您还可以将切入点定义为

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

回答by Donatello

The simplest way seems to be :

最简单的方法似乎是:

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

   return pjp.proceed();

   // perform actions after
}

It will intercept execution of all methods specifically annotated with '@MyHandling' in 'YourService' class. To intercept all methods without exception, just put the annotation directly on the class.

它将拦截在“YourService”类中用“@MyHandling”特别注释的所有方法的执行。要无一例外地拦截所有方法,只需将注解直接放在类上即可。

No matter of the private / public scope here, but keep in mind that spring-aop cannot use aspect for method calls in same instance (typically private ones), because it doesn't use the proxy class in this case.

无论这里的私有/公共范围如何,但请记住,spring-aop 不能在同一实例(通常是私有的)中对方法调用使用方面,因为在这种情况下它不使用代理类。

We use @Around advice here, but it's basically the same syntax with @Before, @After or any advice.

我们在这里使用@Around 建议,但它与@Before、@After 或任何建议的语法基本相同。

By the way, @MyHandling annotation must be configured like this :

顺便说一句,@MyHandling 注释必须像这样配置:

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

}

回答by Alex

Using annotations, as described in the question.

使用注释,如问题中所述。

Annotation: @Monitor

注解: @Monitor

Annotation on class, app/PagesController.java:

类注释,app/PagesController.java

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

Annotation on method, app/PagesController.java:

方法注释,app/PagesController.java

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

Custom annotation, app/Monitor.java:

自定义注释,app/Monitor.java

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

Aspect for annotation, app/MonitorAspect.java:

注释方面,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());
    }
}

Enable AspectJ, servlet-context.xml:

启用AspectJ的,servlet-context.xml

<aop:aspectj-autoproxy />

Include AspectJ libraries, pom.xml:

包括 AspectJ 库,pom.xml

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

回答by Vikram

You could use Spring's PerformanceMonitoringInterceptor and programmatically register the advice using a beanpostprocessor.

您可以使用 Spring 的 PerformanceMonitoringInterceptor 并使用 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;
    }
  }
}

回答by marcocast

it should be enough to mark your aspect method like this:

像这样标记你的方面方法应该就足够了:

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

have a look at thisfor a step by step guide on this.

看一看一步一步的指南。

回答by xmedeko

From Spring's AnnotationTransactionAspect:

从春天的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 *);

回答by Davide Consonni

Use

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