Методы сопоставления точек с аннотированными параметрами - PullRequest
17 голосов
/ 04 мая 2010

Мне нужно создать аспект с pointcut, соответствующим методу, если:

  • Публично
  • Его класс аннотирован @Controller (наконец, нет)
  • Один из его параметров (может иметь много) помечается @ MyParamAnnotation.

Я думаю, что первые два условия просты, но я не знаю, возможно ли выполнить третье с помощью Spring. Если это не так, может быть, я могу изменить его на:

  • Один из его параметров является экземпляром типа com.me.MyType (или реализует некоторый интерфейс)

Как вы думаете, возможно ли достичь этого? И будет ли производительность хорошей?

Спасибо

РЕДАКТИРОВАТЬ : Один из примеров метода сопоставления. Как видите, MyMethod не аннотирован (но может быть).

@Controller
public class MyClass {
    public void MyMethod (String arg0, @MyParamAnnotation Object arg1, Long arg3) {
        ...
    }
}

EDIT : Решение, которое я наконец-то использовал, основано на ответах @Espen. Как видите, я немного изменил свои условия: на самом деле класс не должен быть @ Controller.

@Around("execution(public * * (.., @SessionInject (*), ..))")
public void methodAround(JoinPoint joinPoint) throws Exception {
    ...
}

1 Ответ

22 голосов
/ 04 мая 2010

Это была интересная проблема, поэтому я создал небольшой пример приложения для решения этой проблемы! (И улучшил его с помощью обратной связи Синухе.)

Я создал DemoController класс, который должен работать в качестве примера для аспекта:

@Controller
public class DemoController {

    public void soSomething(String s, @MyParamAnnotation Double d, Integer i) {
    }

    public void doSomething(String s, long l, @MyParamAnnotation int i) {
    }

    public void doSomething(@MyParamAnnotation String s) {
    }

    public void doSomething(long l) {
    }
}

Аспект, который добавит точку соединения к первым трем методам, но не последний метод, где параметр не помечен @MyParamAnnotation:

@Aspect
public class ParameterAspect {

    @Pointcut("within(@org.springframework.stereotype.Controller *)")
    public void beanAnnotatedWithAtController() {
    }

    @Pointcut("execution(public * *(.., @aspects.MyParamAnnotation (*), ..))")
    public void methodWithAnnotationOnAtLeastOneParameter() {
    }

    @Before("beanAnnotatedWithAtController() " 
            + "&& methodWithAnnotationOnAtLeastOneParameter()")
    public void beforeMethod() {    
        System.out.println("At least one of the parameters are " 
                  + "annotated with @MyParamAnnotation");
    }
}

Первый pointcut создаст точку соединения для всех методов внутри классов, помеченных @Controller.

Второй pointcut добавит точку соединения, когда будут выполнены следующие условия:

  • публичный метод
  • first * - подстановочный знак для каждого типа возвращаемого значения.
  • second * - шаблон для всех методов всех классов.
  • (.., соответствует нулю многим параметрам любого типа перед аннотированным параметром.
  • @aspects.MyParamAnnotation (*), соответствует параметру, аннотированному данной аннотацией.
  • ..) соответствует нулю многим параметрам любого типа после аннотированного параметра.

Наконец, совет @Before рекомендует все методы, при которых все условия в обеих точках выполняются.

Pointcut работает как с AspectJ, так и с Spring AOP!

Когда дело касается производительности. Накладные расходы невелики, особенно с AspectJ, который выполняет переплетение во время компиляции или загрузки.

...