2010-01-06 128 views
94

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

+0

下面的一个工程的延伸。 @Pointcut(“execution(*(@ org.rejeev.Monitor *)。*(..))”) 但是现在这个建议正在执行两次。任何线索? – 2010-01-06 08:32:01

+0

另一点是@Monitor注释位于一个接口上,并有一个类实现它。接口和类的存在是否会导致这种建议的双重执行? – 2010-01-06 12:18:57

+4

你应该接受下面的优秀答案。这给他的声誉。这里有很少的人可以回答AspectJ的问题。 – fool4jesus 2013-11-12 17:38:38

回答

10

类似的东西:

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

请注意,你不能此人之前都在同一类任何其他建议,因为注释将进行代理后丢失。

133

你应该结合一个类型切入点和方法切入点。

这些切入点就做好找到标有注释@Monitor一个类中的所有公共方法:

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

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

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

咨询最后切入点,结合了前两个,你就大功告成了!

如果你有兴趣,我写了一个cheat sheet与@AspectJ风格在这里与相应的example document在这里。

+0

谢谢。讨论您的备忘单中的注释切入点特别有用。 – GregHNZ 2013-02-07 22:11:03

+1

我如何在建议中获得对类的引用我使用正常的切入点建议的方式是 @Before(“onObjectAction()&& this(obj)”) – expressions 2013-07-29 07:35:50

+0

该备忘单非常有帮助,即使已经5年:) – 2015-02-19 13:16:44

3

您也可以定义为切入点

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

简单一点''执行(public * @Monitor *。*(..))'也可以。 – xmedeko 2014-12-19 09:12:23

2

最简单的方法似乎是:

@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不能在同一个实例中使用aspect方法调用(通常是私有方法),因为在这种情况下它不使用代理类。

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

顺便提一下,@MyHandling注释必须配置是这样的:

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

} 
+0

这是不回答原来的声明,与ElementType.Type – Alex 2012-05-15 00:07:28

+0

是的,ElementType.TYPE也将允许直接放在类上的注释,我想,将导致处理这个类中的任何方法。我真的吗?它真的有用吗? – Donatello 2012-05-24 12:26:47

+0

'//执行'后面的动作将永远不会被调用,因为我们之前返回行中的值。 – josephpconley 2017-04-21 15:34:01

43

使用注释,如在问题说明。

译注:@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> 
+1

不错的例子。一个问题:为什么Annotation'Monitor'必须是Spring'Component'? – mwhs 2013-11-22 16:36:14

+1

'Component'注释用于告诉Spring容器应用AspectJ weaver中包含的类。默认情况下,Spring只查看'Controller','Service'和其他特定的注释,而不是'Aspect'。 – Alex 2013-11-22 20:46:45

+1

好的,谢谢。但是我在讨论'@ interface'上的'@ Component'注释而不是'Aspect'。为什么需要? – mwhs 2013-11-23 19:18:43

0

你可以使用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; 
    } 
    } 
} 
3

应该足够,以纪念你的一方面方法是这样的:

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

看看this对这样的一步一步的指导。

1

从Spring的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 *); 
0

使用

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