145

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

4

10 回答 10

191

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

这些切入点将用于查找标有 @Monitor 注释的类中的所有公共方法:

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

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

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

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

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

于 2010-03-26T11:22:36.763 回答
72

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

注解:@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>
于 2012-05-15T00:54:41.767 回答
16

像这样的东西:

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

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

于 2010-01-06T07:13:05.200 回答
14

利用

@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
    public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
于 2017-06-25T13:05:37.630 回答
6

像这样标记您的方面方法就足够了:

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

看看这个关于这个的分步指南。

于 2013-07-01T08:14:24.240 回答
3

最简单的方法似乎是:

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

   return pjp.proceed();

   // perform actions after
}

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

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

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

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

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

}
于 2011-06-24T09:40:34.540 回答
3

您还可以将切入点定义为

public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
于 2011-01-11T21:34:16.143 回答
3

我与您分享一个有用的代码,它是创建一个可以在类或方法中使用的注释。

@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface AnnotationLogger {
    /**
     * It is the parameter is to show arguments in the method or the class.
     */
    boolean showArguments() default false;
}


@Aspect
@Component
public class AnnotationLoggerAspect {
    
    @Autowired 
    private Logger logger;  
    
    private static final String METHOD_NAME   = "METHOD NAME: {} ";
    private static final String ARGUMENTS     = "ARGS: {} ";
    
    @Before(value = "@within(com.org.example.annotations.AnnotationLogger) || @annotation(com.org.example.annotations.AnnotationLogger)")
    public void logAdviceExecutionBefore(JoinPoint joinPoint){  
        CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
        AnnotationLogger annotationLogger = getAnnotationLogger(joinPoint);
        if(annotationLogger!= null) {
            StringBuilder annotationLoggerFormat = new StringBuilder();
            List<Object> annotationLoggerArguments = new ArrayList<>();
            annotationLoggerFormat.append(METHOD_NAME);
            annotationLoggerArguments.add(codeSignature.getName());
            
            if (annotationLogger.showArguments()) {
                annotationLoggerFormat.append(ARGUMENTS);
                List<?> argumentList = Arrays.asList(joinPoint.getArgs());
                annotationLoggerArguments.add(argumentList.toString());
            }
            logger.error(annotationLoggerFormat.toString(), annotationLoggerArguments.toArray());
        }
    }
    
    private AnnotationLogger getAnnotationLogger(JoinPoint joinPoint) {
        AnnotationLogger annotationLogger = null;
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = joinPoint.getTarget().getClass().
                    getMethod(signature.getMethod().getName(), signature.getMethod().getParameterTypes());
            
            if (method.isAnnotationPresent(AnnotationLogger.class)){
                annotationLogger = method.getAnnotation(AnnotationLoggerAspect.class);
            }else if (joinPoint.getTarget().getClass().isAnnotationPresent(AnnotationLoggerAspect.class)){
                annotationLogger = joinPoint.getTarget().getClass().getAnnotation(AnnotationLoggerAspect.class);
            }
            return annotationLogger;
        }catch(Exception e) {
            return annotationLogger;
        }
    }
}
于 2020-09-09T18:05:01.580 回答
2

来自春天的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 *);
于 2014-12-19T11:25:27.723 回答
1

您可以使用 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;
    }
  }
}
于 2013-04-23T01:04:54.707 回答