2010-01-06 116 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 { 
} 
相關問題