Метод перехвата с помощью Spring AOP с использованием только аннотаций

В моем файле контекста Spring у меня есть что-то вроде этого:

<bean id="userCheck" class="a.b.c.UserExistsCheck"/>
<aop:config>
      <aop:aspect ref="userCheck">
         <aop:pointcut id="checkUser"
                expression="execution(* a.b.c.d.*.*(..)) &amp;&amp; args(a.b.c.d.RequestObject)"/>
         <aop:around pointcut-ref="checkUser" method="checkUser"/>
      </aop:aspect>
</aop:config>    

a.b.c.UserExistsCheck выглядит так:

@Aspect
public class UserExistsCheck {

@Autowired
private UserInformation userInformation;

public Object checkUser(ProceedingJoinPoint pjp) throws Throwable {
    int userId = ... //get it from the RequestObject passed as a parameter
    if (userExists(userId)) {
        return pjp.proceed();
    } else {
        return new ResponseObject("Invalid user);
    }
}

И класс, который перехватывается с этим материалом, выглядит так:

public class Klazz {
    public ResponseObject doSomething(RequestObject request) {...}
}

Это работает. UserExistCheck выполняется по желанию до того, как вызов будет передан Klazz. Проблема в том, что это единственный способ заставить меня работать. Чтобы заставить это работать, используя аннотации вместо файла контекста, кажется, это слишком сложно для моего маленького мозга. Итак... как именно мне аннотировать методы в UserExistsCheck и Klazz? А нужно ли мне еще что-то? Другой класс? Еще что-то в файле контекста?


person fish    schedule 10.04.2010    source источник


Ответы (3)


Вы включили АОП на основе аннотаций? документация говорит, что вы должны добавить

<aop:aspectj-autoproxy/>

к вашей весенней конфигурации. Затем вам нужно добавить аннотацию перед вашим методом checkUser. Похоже, вам нужен @Around совет, как описано здесь.

@Aspect
public class UserExistsCheck {

  @Around("execution(* a.b.c.d.*.*(..)) && args(a.b.c.d.RequestObject)")
  public Object checkUser(ProceedingJoinPoint pjp) throws Throwable {
person John    schedule 10.04.2010
comment
Да, я включил ‹aop:aspectj-autoproxy/› с самого начала. Я тоже пробовал это, но не работает, метод checkUser никогда не вызывается :( - person fish; 10.04.2010
comment
На самом деле это действительно сработало, просто у меня была глупая ошибка в аргументах, спасибо! Теперь мне интересно, что я сделал неправильно изначально, прежде чем попробовать подход к контекстному файлу... - person fish; 10.04.2010

Из предоставленного вами примера кода видно, что вы пытаетесь создать совет для класса, который не реализует никаких интерфейсов. Как описано в Механизмы проксирования раздел документов Spring, если вы собираетесь это сделать, вам нужно включить CGLIB:

<aop:aspectj-autoproxy proxy-target-class="true" />

Я лично обнаружил, что это немного более привередливо, чем указано в документации, и хотя это работает, если все звезды выровнены правильно, часто проще - и предпочтительнее с точки зрения дизайна - объявить ваш АОП-совет по интерфейсу выглядит следующим образом. (Обратите внимание, что вам потребуется получить экземпляр KlazzImpl из BeanFactory/ApplicationContext.)

public interface Klazz {
  ResponseObject doSomething(RequestObject request);
}

public class KlazzImpl implements Klazz {
  public ResponseObject doSomething(RequestObject request) {...}
}

Кроме того, вы немного неправильно используете выражение args. См. следующее:

@Aspect
public class UserExistsCheck {
  @Autowired
  private UserInformation userInformation;

  @Around("execution(* a.b.c.d.*.*(..)) && args(reqObj)")
  public Object checkUser(ProceedingJoinPoint pjp, a.b.c.d.RequestObject reqObj) throws Throwable {
      // ...
  }
}

Эти изменения должны работать.

person RTBarnard    schedule 10.04.2010
comment
Спасибо за советы, на самом деле Klazz реализует интерфейс, но я использую автопроводку Spring для создания экземпляра. Извините, что не сообщил об этом, я думал, что это не имеет значения. В любом случае вся информация полезная, спасибо! - person fish; 10.04.2010

с весны 3.1 добавьте @EnableAspectJAutoProxy(proxyTargetClass=true) к вашему @Configuraiton

person Ivan Velykorodnyy    schedule 28.08.2012