web-dev-qa-db-ja.com

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);
        }

コンパイル時エラーは発生しませんが、jettyサーバーを起動すると次の例外が発生します。

ネストされた例外はJava.lang.IllegalStateExceptionです:スレッドバインドリクエストが見つかりません:実際のWebリクエスト以外のリクエスト属性を参照していますか、それとも元の受信スレッド外でリクエストを処理していますか?実際にWebリクエスト内で操作しているにもかかわらずこのメッセージを受信する場合、コードはおそらくDispatcherServlet/DispatcherPortletの外部で実行されています。この場合、RequestContextListenerまたはRequestContextFilterを使用して現在のリクエストを公開します。

ここで注意すべきことは、「logAroundService」メソッドを削除しても例外が発生しないことです。

19
riship89

アスペクトに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;
}
16
M. Deinum

エラーメッセージが言ったように:この場合、RequestContextListenerまたはRequestContextFilterを使用して現在のリクエストを公開します。

修正するには、web.xmlファイルにRequestContextListenerリスナーを登録します。

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

@M。 Deinumの回答は私には機能しません。代わりにこれらのコードを使用します

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

ポイントカット式を使用すると、基本的にすべてのBeanをプロキシし、そのアドバイスを適用します。いくつかのBeanが存在し、HttpServletRequestのコンテキスト外で動作します。これは、取得できないことを意味します。

HttpServletRequestは、サーブレットコンテナリクエスト処理スレッドが通過する場所にのみ挿入できます。