Belirli bir ek açıklamaya sahip bir sınıfın tüm yöntemleri için @AspectJ pointcut


127

Belirtilen açıklama ile tüm Sınıfların tüm genel yöntemlerini izlemek istiyorum (@ Monitor diyelim) (not: Ek açıklama sınıf düzeyindedir). Bunun için olası bir nokta ne olabilir? Not: @AspectJ tarzı Yay AOP kullanıyorum.


Aşağıdakiler bir uzatma için çalışıyor. @Pointcut ("execution (* (@ org.rejeev.Monitor *). * (..))") Ancak şimdi tavsiye iki kez uygulanıyor. Bir ipucu?
Rejeev Divakaran

Diğer bir nokta da @Monitor açıklamasının bir arayüzde olması ve bir sınıfın bunu uygulamasıdır. Bir arayüzün ve sınıfın varlığı bu tür tavsiyelerin iki kez yürütülmesine neden olur mu?
Rejeev Divakaran

6
Aşağıdaki mükemmel cevabı kabul etmelisiniz. Bu ona itibar kazandırır. SO'da AspectJ sorularına cevap verebilecek çok az sayıda insan var.
fool4jesus

Yanıtlar:


164

Yazım noktasını bir yöntem nokta kesimi ile birleştirmelisiniz.

Bu nokta kesimleri, @Monitor ek açıklamasıyla işaretlenmiş bir sınıf içindeki tüm genel yöntemleri bulmak için çalışacaktır:

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

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

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

İlk ikisini birleştiren son noktayı tavsiye edin ve bitirdiniz!

Eğer ilgileniyorsanız, buraya @AspectJ stiliyle bir hile sayfası yazdım ve burada karşılık gelen bir örnek belge .


Teşekkürler. Hile Sayfanızdaki Ek açıklama nokta kesimleri tartışması özellikle yararlıdır.
GregHNZ

1
Tavsiyede sınıfa nasıl referans olabilirim, normal noktasal tavsiyelerde yaptığım gibi @Before ("onObjectAction () && this (obj)")
Priyadarshi Kunal

Hile Sayfası 5 yıl geçmiş olmasına rağmen çok yardımcı oldu :)
Yadu Krishnan

Burada sadece bir soru, hiyerarşide olan ve her ikisi de nokta kesiminin altına düşen ve aynı sınıfa ait olan iki yöntem, her ikisinde de yürütülecek mi? Evet ise, o zaman stackoverflow.com/questions/37583539/… adresini ziyaret edin , çünkü bu benim durumumda gerçekleşmiyor.
HVT7

Herkese açık yürütmenin gereksiz olduğunu düşünüyorum çünkü özel yöntemlerde bir nokta kesemezsiniz
amstegraf

58

Soruda açıklandığı gibi ek açıklamaları kullanma.

Ek Açıklama: @Monitor

Sınıftaki ek açıklama app/PagesController.java:

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

Yöntemle ilgili ek açıklama app/PagesController.java:

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

Özel açıklama, app/Monitor.java:

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

Ek açıklama yönü 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 etkinleştirme servlet-context.xml:

<aop:aspectj-autoproxy />

AspectJ kitaplıklarını dahil et pom.xml:

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

1
Güzel örnek. Bir soru: Ek Açıklama neden MonitorBahar olmak zorunda Component?
mwhs

1
ComponentEk açıklama şey dokumacı AspectJ sınıfı dahil uygulamak için Bahar kabı anlatmak için kullanılır. Varsayılan olarak, Bahar sadece bakar Controller, Serviceancak, ve diğer özel ek açıklamaları Aspect.
Alex

1
Tamam teşekkürler. Ama bahsediyordu @Componentüzerinde açıklama @interfacedeğil Aspect. Buna neden ihtiyaç var?
mwhs

2
@ComponentYay AspectJ'yi IoC / DI yönü yönelimli sistemi ile derlenir nedenle açıklama yapar. Nasıl farklı söyleyeceğimi bilmiyorum. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
Alex

Bu, açıklamalı sınıflarda yalnızca "genel" yöntemleri mi yapıyor yoksa tüm yöntemleri mi yapıyor (hangi erişim düzeyi ne olursa olsun)?
Lee Meador

14

Bunun gibi bir şey:

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

Bu sınıftan önce aynı sınıfla ilgili başka bir tavsiyeniz olmamasına dikkat edin , çünkü ek açıklamalar proxy uygulandıktan sonra kaybolacaktır.


11

kullanım

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

4

görünüm yönteminizi şu şekilde işaretlemeniz yeterli olmalıdır:

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

bir göz bu bu konuda adım kılavuz bir adım için.


3

Ayrıca nokta kesimini şu şekilde tanımlayabilirsiniz:

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

Biraz daha basit execution(public * @Monitor *.*(..))işler de.
xmedeko

3

En basit yol şöyle görünüyor:

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

   return pjp.proceed();

   // perform actions after
}

'YourService' sınıfında '@MyHandling' ile özellikle açıklanmış tüm yöntemlerin yürütülmesini durdurur. İstisnasız tüm yöntemleri kesmek için, açıklamayı doğrudan sınıfa koyun.

Buradaki özel / genel kapsam ne olursa olsun, ancak spring-aop'un aynı örnekteki (tipik olarak özel olanlar) yöntem çağrıları için açı kullanamayacağını unutmayın, çünkü bu durumda proxy sınıfını kullanmaz.

Burada @Around tavsiye kullanıyoruz, ancak temelde @Before, @After veya herhangi bir tavsiye ile aynı sözdizimi.

Bu arada, @MyHandling ek açıklaması şu şekilde yapılandırılmalıdır:

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

}

ElementType ile orijinal ifadeyi yanıtlamıyor.Type
Alex

evet, ElementType.TYPE ayrıca sınıflara doğrudan açıklama koymaya da izin verecek, ki bu sınıftaki herhangi bir yöntemi ele alacaktır. Ben doğru muyum Gerçekten çalışıyor mu?
Donatello

Daha // perform actions afterönce satırdaki değeri döndürdüğümüz için asla aranmayacak.
josephpconley

1

Spring'in PerformanceMonitoringInterceptor'ını kullanabilir ve bir beanpostprocessor kullanarak tavsiyeleri programlı olarak kaydedebilirsiniz.

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

1

İlkbahardan itibaren 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 *);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.