From adb54b2c699db07086cc60e1c6c1508c10365d2b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 11 May 2015 19:58:36 +0200 Subject: [PATCH] Backported DispatcherServlet and ServletContextResourcePatternResolver refinements Issue: SPR-13011 --- ...ServletContextResourcePatternResolver.java | 25 +-- .../web/servlet/DispatcherServlet.java | 157 ++++++++++-------- 2 files changed, 101 insertions(+), 81 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResourcePatternResolver.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResourcePatternResolver.java index 378bd8e6e5..e33a0928a7 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResourcePatternResolver.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextResourcePatternResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,8 +37,8 @@ import org.springframework.util.StringUtils; /** * ServletContext-aware subclass of {@link PathMatchingResourcePatternResolver}, * able to find matching resources below the web application root directory - * via Servlet 2.3's {@code ServletContext.getResourcePaths}. - * Falls back to the superclass' file system checking for other resources. + * via {@link ServletContext#getResourcePaths}. Falls back to the superclass' + * file system checking for other resources. * * @author Juergen Hoeller * @since 1.1.2 @@ -160,15 +160,20 @@ public class ServletContextResourcePatternResolver extends PathMatchingResourceP } try { JarFile jarFile = new JarFile(jarFilePath); - for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { - JarEntry entry = entries.nextElement(); - String entryPath = entry.getName(); - if (getPathMatcher().match(entryPattern, entryPath)) { - result.add(new UrlResource( - ResourceUtils.URL_PROTOCOL_JAR, - ResourceUtils.FILE_URL_PREFIX + jarFilePath + ResourceUtils.JAR_URL_SEPARATOR + entryPath)); + try { + for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { + JarEntry entry = entries.nextElement(); + String entryPath = entry.getName(); + if (getPathMatcher().match(entryPattern, entryPath)) { + result.add(new UrlResource( + ResourceUtils.URL_PROTOCOL_JAR, + ResourceUtils.FILE_URL_PREFIX + jarFilePath + ResourceUtils.JAR_URL_SEPARATOR + entryPath)); + } } } + finally { + jarFile.close(); + } } catch (IOException ex) { if (logger.isWarnEnabled()) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java index 62df58a0ea..cae3fabaae 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,73 +59,89 @@ import org.springframework.web.util.NestedServletException; import org.springframework.web.util.WebUtils; /** - * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service - * exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception - * handling facilities. + * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers + * or HTTP-based remote service exporters. Dispatches to registered handlers for processing + * a web request, providing convenient mapping and exception handling facilities. * - *

This servlet is very flexible: It can be used with just about any workflow, with the installation of the - * appropriate adapter classes. It offers the following functionality that distinguishes it from other request-driven - * web MVC frameworks: + *

This servlet is very flexible: It can be used with just about any workflow, with the + * installation of the appropriate adapter classes. It offers the following functionality + * that distinguishes it from other request-driven web MVC frameworks: * - *

  • It is based around a JavaBeans configuration mechanism. + *
      + *
    • It is based around a JavaBeans configuration mechanism. * - *
    • It can use any {@link HandlerMapping} implementation - pre-built or provided as part of an application - to - * control the routing of requests to handler objects. Default is {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} - * and {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}. HandlerMapping objects - * can be defined as beans in the servlet's application context, implementing the HandlerMapping interface, overriding - * the default HandlerMapping if present. HandlerMappings can be given any bean name (they are tested by type). + *
    • It can use any {@link HandlerMapping} implementation - pre-built or provided as part + * of an application - to control the routing of requests to handler objects. Default is + * {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} and + * {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}. + * HandlerMapping objects can be defined as beans in the servlet's application context, + * implementing the HandlerMapping interface, overriding the default HandlerMapping if + * present. HandlerMappings can be given any bean name (they are tested by type). * - *
    • It can use any {@link HandlerAdapter}; this allows for using any handler interface. Default adapters are {@link - * org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter}, {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}, - * for Spring's {@link org.springframework.web.HttpRequestHandler} and {@link org.springframework.web.servlet.mvc.Controller} - * interfaces, respectively. A default {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} - * will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the - * default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type). + *
    • It can use any {@link HandlerAdapter}; this allows for using any handler interface. + * Default adapters are {@link org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter}, + * {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}, for Spring's + * {@link org.springframework.web.HttpRequestHandler} and + * {@link org.springframework.web.servlet.mvc.Controller} interfaces, respectively. A default + * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} + * will be registered as well. HandlerAdapter objects can be added as beans in the + * application context, overriding the default HandlerAdapters. Like HandlerMappings, + * HandlerAdapters can be given any bean name (they are tested by type). * - *
    • The dispatcher's exception resolution strategy can be specified via a {@link HandlerExceptionResolver}, for - * example mapping certain exceptions to error pages. Default are + *
    • The dispatcher's exception resolution strategy can be specified via a + * {@link HandlerExceptionResolver}, for example mapping certain exceptions to error pages. + * Default are * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver}, * {@link org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver}, and - * {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}. These HandlerExceptionResolvers can be overridden - * through the application context. HandlerExceptionResolver can be given any bean name (they are tested by type). + * {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}. + * These HandlerExceptionResolvers can be overridden through the application context. + * HandlerExceptionResolver can be given any bean name (they are tested by type). * - *
    • Its view resolution strategy can be specified via a {@link ViewResolver} implementation, resolving symbolic view - * names into View objects. Default is {@link org.springframework.web.servlet.view.InternalResourceViewResolver}. - * ViewResolver objects can be added as beans in the application context, overriding the default ViewResolver. - * ViewResolvers can be given any bean name (they are tested by type). + *
    • Its view resolution strategy can be specified via a {@link ViewResolver} + * implementation, resolving symbolic view names into View objects. Default is + * {@link org.springframework.web.servlet.view.InternalResourceViewResolver}. + * ViewResolver objects can be added as beans in the application context, overriding the + * default ViewResolver. ViewResolvers can be given any bean name (they are tested by type). * - *
    • If a {@link View} or view name is not supplied by the user, then the configured {@link - * RequestToViewNameTranslator} will translate the current request into a view name. The corresponding bean name is - * "viewNameTranslator"; the default is {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}. + *
    • If a {@link View} or view name is not supplied by the user, then the configured + * {@link RequestToViewNameTranslator} will translate the current request into a view name. + * The corresponding bean name is "viewNameTranslator"; the default is + * {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}. * - *
    • The dispatcher's strategy for resolving multipart requests is determined by a {@link - * org.springframework.web.multipart.MultipartResolver} implementation. Implementations for Jakarta Commons FileUpload - * and Jason Hunter's COS are included; the typical choise is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}. + *
    • The dispatcher's strategy for resolving multipart requests is determined by a + * {@link org.springframework.web.multipart.MultipartResolver} implementation. + * Implementations for Apache Commons FileUpload and Servlet 3 are included; the typical + * choice is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}. * The MultipartResolver bean name is "multipartResolver"; default is none. * - *
    • Its locale resolution strategy is determined by a {@link LocaleResolver}. Out-of-the-box implementations work via - * HTTP accept header, cookie, or session. The LocaleResolver bean name is "localeResolver"; default is {@link - * org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}. + *
    • Its locale resolution strategy is determined by a {@link LocaleResolver}. + * Out-of-the-box implementations work via HTTP accept header, cookie, or session. + * The LocaleResolver bean name is "localeResolver"; default is + * {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}. * - *
    • Its theme resolution strategy is determined by a {@link ThemeResolver}. Implementations for a fixed theme and for - * cookie and session storage are included. The ThemeResolver bean name is "themeResolver"; default is {@link - * org.springframework.web.servlet.theme.FixedThemeResolver}.
    + *
  • Its theme resolution strategy is determined by a {@link ThemeResolver}. + * Implementations for a fixed theme and for cookie and session storage are included. + * The ThemeResolver bean name is "themeResolver"; default is + * {@link org.springframework.web.servlet.theme.FixedThemeResolver}. + *
* - *

NOTE: The {@code @RequestMapping} annotation will only be processed if a corresponding - * {@code HandlerMapping} (for type level annotations) and/or {@code HandlerAdapter} (for method level - * annotations) is present in the dispatcher. This is the case by default. However, if you are defining custom - * {@code HandlerMappings} or {@code HandlerAdapters}, then you need to make sure that a corresponding custom - * {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter} is defined as well - - * provided that you intend to use {@code @RequestMapping}. + *

NOTE: The {@code @RequestMapping} annotation will only be processed if a + * corresponding {@code HandlerMapping} (for type-level annotations) and/or + * {@code HandlerAdapter} (for method-level annotations) is present in the dispatcher. + * This is the case by default. However, if you are defining custom {@code HandlerMappings} + * or {@code HandlerAdapters}, then you need to make sure that a corresponding custom + * {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter} + * is defined as well - provided that you intend to use {@code @RequestMapping}. * - *

A web application can define any number of DispatcherServlets. Each servlet will operate in its own - * namespace, loading its own application context with mappings, handlers, etc. Only the root application context as - * loaded by {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared. + *

A web application can define any number of DispatcherServlets. + * Each servlet will operate in its own namespace, loading its own application context + * with mappings, handlers, etc. Only the root application context as loaded by + * {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared. * *

As of Spring 3.1, {@code DispatcherServlet} may now be injected with a web * application context, rather than creating its own internally. This is useful in Servlet - * 3.0+ environments, which support programmatic registration of servlet instances. See - * {@link #DispatcherServlet(WebApplicationContext)} Javadoc for details. + * 3.0+ environments, which support programmatic registration of servlet instances. + * See the {@link #DispatcherServlet(WebApplicationContext)} javadoc for details. * * @author Rod Johnson * @author Juergen Hoeller @@ -851,12 +867,11 @@ public class DispatcherServlet extends FrameworkServlet { doDispatch(request, response); } finally { - if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { - return; - } - // Restore the original attribute snapshot, in case of an include. - if (attributesSnapshot != null) { - restoreAttributesAfterInclude(request, attributesSnapshot); + if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { + // Restore the original attribute snapshot, in case of an include. + if (attributesSnapshot != null) { + restoreAttributesAfterInclude(request, attributesSnapshot); + } } } } @@ -885,7 +900,7 @@ public class DispatcherServlet extends FrameworkServlet { try { processedRequest = checkMultipart(request); - multipartRequestParsed = processedRequest != request; + multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); @@ -914,14 +929,11 @@ public class DispatcherServlet extends FrameworkServlet { return; } - try { - // Actually invoke the handler. - mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); - } - finally { - if (asyncManager.isConcurrentHandlingStarted()) { - return; - } + // Actually invoke the handler. + mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); + + if (asyncManager.isConcurrentHandlingStarted()) { + return; } applyDefaultViewName(request, mv); @@ -941,12 +953,15 @@ public class DispatcherServlet extends FrameworkServlet { finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion - mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); - return; + if (mappedHandler != null) { + mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); + } } - // Clean up any resources used by a multipart request. - if (multipartRequestParsed) { - cleanupMultipart(processedRequest); + else { + // Clean up any resources used by a multipart request. + if (multipartRequestParsed) { + cleanupMultipart(processedRequest); + } } } } @@ -1255,7 +1270,7 @@ public class DispatcherServlet extends FrameworkServlet { } private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response, - HandlerExecutionChain mappedHandler, Error error) throws Exception, ServletException { + HandlerExecutionChain mappedHandler, Error error) throws Exception { ServletException ex = new NestedServletException("Handler processing failed", error); if (mappedHandler != null) {