2016-12-01 17 views
1

У меня есть проблема с Аспектом я кодированной:Spring AOP @Around совет стрельба два раза при возвращении ResponseEntity

@Aspect 
@Component 
public class MyAudit { 

@Pointcut("@annotation(requestMapping)") 
public void controller(RequestMapping requestMapping) { 
} 

@Around("controller(requestMapping)") 
public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {   

... 

В одном пути коды, я делаю поиск для авторизации, и мне нужно, чтобы вернуть данные пользователю БЕЗ выполнения метода. В принципе, мне нужно выскочить из потока.

У меня есть код, как это:

log.warn("Not permitted per policy. Returning without executing: " + authError);  
    Map<String,String> responseBody = new HashMap<>(); 
    responseBody.put("path",request.getContextPath()); 
    responseBody.put("message",authError); 
    return new ResponseEntity<>(responseBody,HttpStatus.OK); 

Проблема заключается в том, что когда я вернусь ResponseEntity, он падает обратно в мой метод «вокруг». Не уверен, почему он выполняется снова.

Кто-то в другой ветке упоминает, что я не должен комментировать это как @Component, но я попытался удалить это, и когда я это сделаю, метод @Around вообще не выполняется.

Может ли кто-нибудь указать, что я делаю неправильно?

UPDATE:

Вот полный класс с некоторым кодом, связанным с бизнесом-конкретных деталей удалены.

import com.ge.aviation.paasport.model.Audit; 
import com.ge.aviation.paasport.repository.AuditRepository; 
import com.ge.aviation.paasport.util.SecurityUtils; 
import static com.google.common.base.Strings.isNullOrEmpty; 
import java.lang.annotation.Annotation; 
import java.util.Calendar; 
import java.util.HashMap; 
import java.util.Map; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.validation.constraints.NotNull; 
import org.apache.http.HttpResponse; 
import org.apache.log4j.Logger; 
import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Pointcut; 
import org.json.JSONObject; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.core.annotation.AnnotationUtils; 
import org.springframework.http.HttpStatus; 
import org.springframework.http.ResponseEntity; 
import org.springframework.stereotype.Component; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.context.request.RequestContextHolder; 
import org.springframework.web.context.request.ServletRequestAttributes; 

@Aspect 
@Component 
public class MyAudit { 

    @Pointcut("@annotation(requestMapping)") 
    public void controller(RequestMapping requestMapping) { 
    } 

    @Around("controller(requestMapping)") 
    public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {   

     String authError = null; 
     HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 

     String decision = SecurityUtils.evaluatePolicy(request); 
     if(!(decision.toUpperCase().equals(SecurityUtils.PERMIT))) { 
      authError = decision + " : Request not permittted per policy."; 
      log.warn("Not permitted per policy. Returning without executing: " + authError);  
      Map<String,String> responseBody = new HashMap<>(); 
      responseBody.put("path",request.getContextPath()); 
      responseBody.put("message",authError); 
      return new ResponseEntity<>(responseBody,HttpStatus.OK); 
     } 
     return pjp.proceed(); 
    } 
} 

Когда он выполняет return new ResponseEntity<>(responseBody,HttpStatus.OK); в @Around совет, он вновь входит метод вокруг 2-й раз.

Я установил точку останова на фактический метод, который будет выполнен в обычном потоке, и он никогда не попадает.

Похоже, что это метод ma.invoke (return ma.invoke(obj, args);), который попадает при возврате ResponseEntity и снова запускается обратно в метод round.

package java.lang.reflect; 

... 
... 

public final class Method extends Executable { 

... 
... 

@CallerSensitive 
    public Object invoke(Object obj, Object... args) 
     throws IllegalAccessException, IllegalArgumentException, 
     InvocationTargetException 
    { 
     if (!override) { 
      if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { 
       Class<?> caller = Reflection.getCallerClass(); 
       checkAccess(caller, clazz, obj, modifiers); 
      } 
     } 
     MethodAccessor ma = methodAccessor;    // read volatile 
     if (ma == null) { 
      ma = acquireMethodAccessor(); 
     } 
     return ma.invoke(obj, args); 
    } 
} 
+0

Пожалуйста, отредактируйте ваше сообщение, включая то, что вы делаете именно в своем совете. Лучше всего было бы, если бы вы включили весь аспект. Кроме того, используете ли вы Spring AOP или AspectJ (есть ли во время исполнения во время сборки во время сборки или во время загрузки во время выполнения)? –

+0

'@annotation (...)' pointcut сам по себе соответствует как выполнению метода, так и методу соединения, поэтому если вы действительно используете AspectJ, это может быть причиной двойного вызова метода. Spring AOP поддерживает только точки соединения с выполнением методов, но по-прежнему стоит добавить '&& execute (...)' к вашему выражению pointcut. Вот почему я спросил, действительно ли вы используете AspectJ или Spring AOP, важно знать, когда пытаетесь выяснить свою проблему. Итак, вот еще вопрос: есть ли во время выполнения компиляция в вашей сборке или во время работы во время загрузки? –

+0

Также см. Этот [ответ] (http: // stackoverflow.com/a/1606780/2699901) для некоторых деталей о различии между AspectJ и Spring AOP. –

ответ

1

Спасибо за помощь. Я понял это ...

В первый раз он вошел в мой метод совет:

pjp = 
    (org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint) 
    execution(List com.myCompany.controller.ApplicationController.getApplications()) 

второй раз войти в метод (после того, как я вернулся мой 401 ответ):

pjp = 
    (org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint) 
    execution(ResponseEntity org.springframework.boot.autoconfigure.web.BasicErrorController.error(HttpServletRequest)) 

я добавил это для моего аспекта:

@Around("@annotation(requestMapping) && execution(* com.myCompany.controller..*.*(..))") 
public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {   

и он выполнен только один раз.

+0

Итак, вы поняли это. Ваш pointcut был слишком широк, перехватывая только все аннотированные '@ RequestMapping'. Как описано в документе, метод [BasicErrorController.error] (http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/web/BasicErrorController.html#error-javax.servlet. http.HttpServletRequest-) также имеет ту же самую аннотацию. Возможно, вы хотите принять свой собственный ответ, чтобы закрыть вопрос. – kriegaex