Java.lang.IllegalStateException: не найден запрос на привязку к потоку, исключение в аспекте

Вот мой аспект:

    @Configurable
    @Aspect
    public class TimingAspect {

        @Autowired
        private HttpServletRequest httpServletRequest;

        // Generic performance logger for any mothod
        private Object logPerfomanceInfo(ProceedingJoinPoint joinPoint, String remoteAddress) {
            StringBuilder tag = new StringBuilder();
            if (joinPoint.getTarget() != null) {
                tag.append(joinPoint.getTarget().getClass().getName());
                tag.append(".");
            }
            tag.append(joinPoint.getSignature().getName());
            StopWatch stopWatch = new StopWatch(tag.toString());
            Object result = joinPoint.proceed(); // continue on the intercepted method
            stopWatch.stop();

            PerformanceUtils.logInPerf4jFormat(stopWatch.getStartTime(), stopWatch.getElapsedTime(), stopWatch.getTag(), stopWatch.getMessage(), remoteAddress);
            return result;
        }

        @Around("execution(* $$$.$$$.$$$.api.controller.*.*(..))")
        public Object logAroundApis(ProceedingJoinPoint joinPoint) throws Throwable {
            String remoteAddress = null;
            if (httpServletRequest != null) {
               remoteAddress = httpServletRequest.getRemoteAddr();
            }
            return logPerfomanceInfo(joinPoint, remoteAddress);
        }

        @Around("execution(* $$$.$$$.$$$.$$$.$$$.$$$.*(..))")
        public Object logAroundService(ProceedingJoinPoint joinPoint) throws Throwable {
            String remoteAddress = null;
            if (httpServletRequest != null) {
                remoteAddress = httpServletRequest.getRemoteAddr();
            }
            return logPerfomanceInfo(joinPoint, remoteAddress);
        }

У меня нет ошибок времени компиляции, но я делаю следующее исключение, когда я запускаю свой сервер причала:

Вложенное исключение - это java.lang.IllegalStateException: Нет связанного с потоком запрос: вы ссылаетесь на атрибуты запроса за пределами фактический веб-запрос или обработка запроса за пределами первоначально принимающая нить? Если вы действительно работаете в веб-запросе и все еще получать это сообщение, ваш код, вероятно, работает за пределами DispatcherServlet/DispatcherPortlet: В этом случае используйте RequestContextListener или RequestContextFilter для отображения текущей запрос.

Следует отметить, что если я удалю метод logAroundService, я не получаю никаких исключений.

Ответ 1

Вы не должны автоопределять HttpServletRequest в своем аспекте, так как это свяжет ваш аспект только для классов, вызываемых из исполняемого HttpServletRequest.

Вместо этого используйте RequestContextHolder, чтобы получить запрос, когда вам это нужно.

private String getRemoteAddress() {
    RequestAttributes attribs = RequestContextHolder.getRequestAttributes();
    if (attribs instanceof NativeWebRequest) {
        HttpServletRequest request = (HttpServletRequest) ((NativeWebRequest) attribs).getNativeRequest();
        return request.getRemoteAddr();
    }
    return null;
}

Ответ 2

Как сказано в сообщении об ошибке: В этом случае используйте RequestContextListener или RequestContextFilter для отображения текущего запроса.

Чтобы исправить это, зарегистрируйте прослушиватель RequestContextListener в файле web.xml.

<web-app ...>
   <listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
   </listener>
</web-app>

Ответ 3

@M. Ответ на Deinum не работает для меня. Вместо этого я использую этот код

RequestAttributes attribs = RequestContextHolder.getRequestAttributes();
if (RequestContextHolder.getRequestAttributes() != null) {
    HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();
    return request.getRemoteAddr();
}

Ответ 4

С помощью выражения pointcut вы в основном проксируете каждый bean и применяете этот совет. Некоторые beans существуют и работают вне контекста HttpServletRequest. Это означает, что он не может быть восстановлен.

Вы можете вводить HttpServletRequest только те места, где проходит поток обработки запроса сервлетов.