2014-11-19 6 views
0

я аннотации, определенным, как показано нижеSpring AOP аспект с аннотациями не работает для базового класса

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

и класс А, определенный ниже

public abstract class A { 
    @OTPFlow 
    public ModelAndView doSomething() { 
    //do something and return ModelAndView 
    } 
} 

класса B представляет собой контроллер определен, как показано ниже

@Controller 
@RequestMapping(value = {"/someurl"}) 
public class B extends A { 
    @RequestMapping(value = {"/get"}, method = {RequestMethod.POST, RequestMethod.GET}) 
    public ModelAndView get(HttpServletRequest request, HttpServletResponse response) { 
    return doSomething(); 
    } 
} 

Аспект определяется как

@Component 
@Aspect 
public class OTPAspect { 
private static final Logger logger = LoggerFactory.getLogger(OTPAspect.class); 

@Pointcut("@annotation(OTPFlow)") 
public void OTPFlow() {} 

@Around("OTPFlow()") 
public Object checkOTP(ProceedingJoinPoint joinPoint) { 
    try { 
     logger.info("Inside Aspect"); 
     return joinPoint.proceed(); 
    } catch (Throwable e) { 
     throw new RuntimeException(e); 
    } 
} 
} 

Проблема в том, что когда я обращаюсь к url ​​"/ someurl/get", аспект не выполняется. Но когда я комментирую метод get get класса B, выполняется аспект.

Так что в основном аннотированные методы суперкласса не вызывают Аспект.

В чем проблема? Есть ли другой способ достичь этого? Любая помощь будет оценена по достоинству. Спасибо

+3

Spring использует прокси, только вызовы метода INTO объекта перехватываются, вы внутренне вызываете метод. –

+0

Здесь есть один вид «работы», который можно сделать, не прибегая к полной AspectJ. Просто создайте компонент «prototype scoped», который даст вам способ создать временный прокси (путем экземпляра экземпляра компонента), а затем, если у вас есть методы на этом компоненте, нацеленные на pointcuts, экземпляр bean будет его собственный прокси-сервер, и поэтому AOP * будет правильно вызван. Очевидно, вы использовали бы это только в ограниченных обстоятельствах и не делали бы его основной частью своей архитектуры, но в тех случаях, когда вам нужно то, что Spring AOP не может обеспечить, этот трюк «прототипа» может работать. –

ответ

1

Я хочу предложите альтернативу тому, что правильно сказали М. Дейн и Мариос: используйте AspectJ вместо Spring AOP. AspectJ не полагается на прокси, быстрее, мощнее и прекрасно интегрируется с Spring, как описано в руководстве Spring, Section 9.8, Using AspectJ with Spring applications. С AspectJ то, что вы хотите делать, работает из коробки.

+0

Ну, это зависит от :). Вы можете использовать AspectJ с пружиной, но все же полагаться на прокси. Что вы имеете в виду, это полноразмерный AspectJ с загрузкой или компиляцией во времени. –

+1

Нет, я имею в виду AspectJ, когда я говорю AspectJ, см. Мою ссылку. Прокси-основанная структура, о которой вы говорите, это * not * AspectJ, это Spring AOP, подход AOP lite, встроенный в Spring, и просто используется подмножество синтаксиса pointpoint AspectJ. – kriegaex

+0

Ну, это не только синтаксис AspectJ, который вы также можете использовать с ним аспекты AspectJ. Хотя действительно для подмножества ('execute' и специальных« боковых »pointcut) точек, доступных для полноразмерного AspectJ. Это то, что делает его несколько неопределенным в том, где заканчивается AspectJ, и начинается Spring AOP .. (Исторически он основывался только на материалах «aopalliance»). –

1

Что происходит, когда весна применяет аспект, это то, что пружина создает прокси-серверы, которые обертывают ваш экземпляр контроллера для перехвата вызовов и добавляют поведение аспект перед вызовом метода экземпляра. Это приводит к тому, что любой вызов «этого» из вашего экземпляра контроллера непосредственно вызывается в этом экземпляре и не будет перехвачен прокси-сервером. Поэтому метод «get» вызывается в прокси-классе, который, в свою очередь, вызовет метод «get» экземпляра контроллера, а когда последний попытается вызвать метод «doSomething», он не пройдет через прокси-сервер «doSomething» », а через внутреннюю.

Способ справиться с этой ситуацией, чтобы применить аспекты непосредственно к методам вашего класса, который будет внешне называется, в вашем случае непосредственно на методе «получить» вместо «DoSomething»

Смежные вопросы