Spring MVC 异常 - 调用请求方法导致异常:public static native long java.lang.System.currentTimeMillis()

发布于 2024-11-01 02:12:26 字数 3737 浏览 0 评论 0原文

我刚刚在日志文件中多次看到此异常:

调用请求方法导致异常:public static native long java.lang.System.currentTimeMillis()

java.lang.IllegalArgumentException: Invalid handler method return value: 1302697287376
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.getModelAndView(AnnotationMethodHandlerExceptionResolver.java:410)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.doResolveException(AnnotationMethodHandlerExceptionResolver.java:140)
    at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:136)
    at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:987)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:811)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.mortbay.servlet.UserAgentFilter.doFilter(UserAgentFilter.java:78)
    at org.mortbay.servlet.GzipFilter.doFilter(GzipFilter.java:154)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)

是的,我的代码都不存在。该异常意味着处理程序方法返回了一个long数字,但它只能返回一组有限的类型。

我没有意识到 System.currentTimeMillis() 是如何实现为处理程序方法的?

I just saw this exception a number of times in my log files:

Invoking request method resulted in exception : public static native long java.lang.System.currentTimeMillis()

java.lang.IllegalArgumentException: Invalid handler method return value: 1302697287376
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.getModelAndView(AnnotationMethodHandlerExceptionResolver.java:410)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver.doResolveException(AnnotationMethodHandlerExceptionResolver.java:140)
    at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:136)
    at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:987)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:811)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.mortbay.servlet.UserAgentFilter.doFilter(UserAgentFilter.java:78)
    at org.mortbay.servlet.GzipFilter.doFilter(GzipFilter.java:154)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)

Yes, none of my code is there. What the exception means is that a handler method has returned a long number, but it can only return a limited set of types.

What I don't realize is how was the System.currentTimeMillis() realized as a handler method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一笑百媚生 2024-11-08 02:12:26

** 更新:这已在 Spring 3.1.2 中修复 **

我相信这确实是由竞争条件引起的。我为其创建了一个 Jira 问题,并尝试解释发生的情况: https:// /jira.springsource.org/browse/SPR-9138

以下是 jira 问题的解释摘录:

private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
    //T1 and T2 enters method
    final Class<?> handlerType = ClassUtils.getUserClass(handler);
    final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
    Method handlerMethod = null;

    Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
    //Timing makes (handlers==null) for T1 (handler != null) for T2
    if (handlers != null) {
        handlerMethod = handlers.get(thrownExceptionType);
        //handlerMethod is still null for T2
        if (handlerMethod != null) {
            return (handlerMethod == NO_METHOD_FOUND ? null : handlerMethod);
        }
    }
    else {
        //T1 does this, the hashmap created here is read by T2 in if-test above matching this else block
        handlers = new ConcurrentHashMap<Class<? extends Throwable>, Method>();
        exceptionHandlerCache.put(handlerType, handlers);
    }

    //handlers is empty for both T1 and T2, the two threads' resolverMethod variables will reference the same
    // ConcurrentHashMap instance
    final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;

    //This block does not find a match for the exception
    ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
        public void doWith(Method method) {
            method = ClassUtils.getMostSpecificMethod(method, handlerType);
            List<Class<? extends Throwable>> handledExceptions = getHandledExceptions(method);
            for (Class<? extends Throwable> handledException : handledExceptions) {
                if (handledException.isAssignableFrom(thrownExceptionType)) {
                    if (!resolverMethods.containsKey(handledException)) {
                        resolverMethods.put(handledException, method);
                    } else {
                        Method oldMappedMethod = resolverMethods.get(handledException);
                        if (!oldMappedMethod.equals(method)) {
                            throw new IllegalStateException(
                                    "Ambiguous exception handler mapped for " + handledException + "]: {" +
                                            oldMappedMethod + ", " + method + "}.");
                        }
                    }
                }
            }
        }
    });
    //T1 finds no match and puts NO_METHOD_FOUND in cache and returns null
    // When T2 hits this line resolverMethods for T2 reference the same Map that T1 just put the NO_METHOD_FOUND
    // as a result getBestMatchingMethod will return NO_SUCH_METHOD_FOUND (System.timeMillis()) which will be invoked
    // by the doResolveException further up the callstack.
    handlerMethod = getBestMatchingMethod(resolverMethods, thrownException);
    handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
    return handlerMethod;
}

** Update: This has been fixed in Spring 3.1.2 **

I believe this is indeed caused by a race condition. I've created a Jira issue for it, where I've tried to explain what happens: https://jira.springsource.org/browse/SPR-9138

Here's an excerpt of the explanation from the jira issue:

private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
    //T1 and T2 enters method
    final Class<?> handlerType = ClassUtils.getUserClass(handler);
    final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
    Method handlerMethod = null;

    Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
    //Timing makes (handlers==null) for T1 (handler != null) for T2
    if (handlers != null) {
        handlerMethod = handlers.get(thrownExceptionType);
        //handlerMethod is still null for T2
        if (handlerMethod != null) {
            return (handlerMethod == NO_METHOD_FOUND ? null : handlerMethod);
        }
    }
    else {
        //T1 does this, the hashmap created here is read by T2 in if-test above matching this else block
        handlers = new ConcurrentHashMap<Class<? extends Throwable>, Method>();
        exceptionHandlerCache.put(handlerType, handlers);
    }

    //handlers is empty for both T1 and T2, the two threads' resolverMethod variables will reference the same
    // ConcurrentHashMap instance
    final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;

    //This block does not find a match for the exception
    ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
        public void doWith(Method method) {
            method = ClassUtils.getMostSpecificMethod(method, handlerType);
            List<Class<? extends Throwable>> handledExceptions = getHandledExceptions(method);
            for (Class<? extends Throwable> handledException : handledExceptions) {
                if (handledException.isAssignableFrom(thrownExceptionType)) {
                    if (!resolverMethods.containsKey(handledException)) {
                        resolverMethods.put(handledException, method);
                    } else {
                        Method oldMappedMethod = resolverMethods.get(handledException);
                        if (!oldMappedMethod.equals(method)) {
                            throw new IllegalStateException(
                                    "Ambiguous exception handler mapped for " + handledException + "]: {" +
                                            oldMappedMethod + ", " + method + "}.");
                        }
                    }
                }
            }
        }
    });
    //T1 finds no match and puts NO_METHOD_FOUND in cache and returns null
    // When T2 hits this line resolverMethods for T2 reference the same Map that T1 just put the NO_METHOD_FOUND
    // as a result getBestMatchingMethod will return NO_SUCH_METHOD_FOUND (System.timeMillis()) which will be invoked
    // by the doResolveException further up the callstack.
    handlerMethod = getBestMatchingMethod(resolverMethods, thrownException);
    handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
    return handlerMethod;
}
蓝色星空 2024-11-08 02:12:26

他们使用 System.currentTimeMillis() 作为异常处理程序方法缓存中的虚拟值:

// dummy method placeholder
private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", null);

并且在争用情况下未经检查就会泄漏(如果由另一个线程在 (1) 和 (2) 之间插入)。或者甚至可能由于 thrownExceptionTypeclosestMatch 之间的差异而没有争用:

private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
    ...
    Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);

    if (handlers != null) {
        handlerMethod = handlers.get(thrownExceptionType); // 1
        if (handlerMethod != null) {
            return (handlerMethod == NO_METHOD_FOUND ? null : handlerMethod);
        }
    }
    ...
    final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;   
    ...
    handlerMethod = getBestMatchingMethod(resolverMethods, thrownException); // 2
    handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
    return handlerMethod;
}

private Method getBestMatchingMethod(
        Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {

    if (!resolverMethods.isEmpty()) {
        Class<? extends Throwable> closestMatch =
                ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
        return resolverMethods.get(closestMatch);
    }
    else {
        return null;
    }
}

请参阅AnnotationMethodHandlerExceptionResolver.java

They use System.currentTimeMillis() as a dummy value in a cache of exception handler methods:

// dummy method placeholder
private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", null);

And it leaks without check under contention (if inserted by another thread between (1) and (2)). Or perhaps even without contention due to difference between thrownExceptionType and closestMatch:

private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
    ...
    Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);

    if (handlers != null) {
        handlerMethod = handlers.get(thrownExceptionType); // 1
        if (handlerMethod != null) {
            return (handlerMethod == NO_METHOD_FOUND ? null : handlerMethod);
        }
    }
    ...
    final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;   
    ...
    handlerMethod = getBestMatchingMethod(resolverMethods, thrownException); // 2
    handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
    return handlerMethod;
}

private Method getBestMatchingMethod(
        Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {

    if (!resolverMethods.isEmpty()) {
        Class<? extends Throwable> closestMatch =
                ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
        return resolverMethods.get(closestMatch);
    }
    else {
        return null;
    }
}

See AnnotationMethodHandlerExceptionResolver.java.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文