Skip to content

Commit adb54b2

Browse files
committed
Backported DispatcherServlet and ServletContextResourcePatternResolver refinements
Issue: SPR-13011
1 parent eb6368c commit adb54b2

File tree

2 files changed

+101
-81
lines changed

2 files changed

+101
-81
lines changed

spring-web/src/main/java/org/springframework/web/context/support/ServletContextResourcePatternResolver.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,8 +37,8 @@
3737
/**
3838
* ServletContext-aware subclass of {@link PathMatchingResourcePatternResolver},
3939
* able to find matching resources below the web application root directory
40-
* via Servlet 2.3's {@code ServletContext.getResourcePaths}.
41-
* Falls back to the superclass' file system checking for other resources.
40+
* via {@link ServletContext#getResourcePaths}. Falls back to the superclass'
41+
* file system checking for other resources.
4242
*
4343
* @author Juergen Hoeller
4444
* @since 1.1.2
@@ -160,15 +160,20 @@ private void doRetrieveMatchingJarEntries(String jarFilePath, String entryPatter
160160
}
161161
try {
162162
JarFile jarFile = new JarFile(jarFilePath);
163-
for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
164-
JarEntry entry = entries.nextElement();
165-
String entryPath = entry.getName();
166-
if (getPathMatcher().match(entryPattern, entryPath)) {
167-
result.add(new UrlResource(
168-
ResourceUtils.URL_PROTOCOL_JAR,
169-
ResourceUtils.FILE_URL_PREFIX + jarFilePath + ResourceUtils.JAR_URL_SEPARATOR + entryPath));
163+
try {
164+
for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
165+
JarEntry entry = entries.nextElement();
166+
String entryPath = entry.getName();
167+
if (getPathMatcher().match(entryPattern, entryPath)) {
168+
result.add(new UrlResource(
169+
ResourceUtils.URL_PROTOCOL_JAR,
170+
ResourceUtils.FILE_URL_PREFIX + jarFilePath + ResourceUtils.JAR_URL_SEPARATOR + entryPath));
171+
}
170172
}
171173
}
174+
finally {
175+
jarFile.close();
176+
}
172177
}
173178
catch (IOException ex) {
174179
if (logger.isWarnEnabled()) {

spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java

Lines changed: 86 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -59,73 +59,89 @@
5959
import org.springframework.web.util.WebUtils;
6060

6161
/**
62-
* Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service
63-
* exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception
64-
* handling facilities.
62+
* Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers
63+
* or HTTP-based remote service exporters. Dispatches to registered handlers for processing
64+
* a web request, providing convenient mapping and exception handling facilities.
6565
*
66-
* <p>This servlet is very flexible: It can be used with just about any workflow, with the installation of the
67-
* appropriate adapter classes. It offers the following functionality that distinguishes it from other request-driven
68-
* web MVC frameworks:
66+
* <p>This servlet is very flexible: It can be used with just about any workflow, with the
67+
* installation of the appropriate adapter classes. It offers the following functionality
68+
* that distinguishes it from other request-driven web MVC frameworks:
6969
*
70-
* <ul> <li>It is based around a JavaBeans configuration mechanism.
70+
* <ul>
71+
* <li>It is based around a JavaBeans configuration mechanism.
7172
*
72-
* <li>It can use any {@link HandlerMapping} implementation - pre-built or provided as part of an application - to
73-
* control the routing of requests to handler objects. Default is {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}
74-
* and {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}. HandlerMapping objects
75-
* can be defined as beans in the servlet's application context, implementing the HandlerMapping interface, overriding
76-
* the default HandlerMapping if present. HandlerMappings can be given any bean name (they are tested by type).
73+
* <li>It can use any {@link HandlerMapping} implementation - pre-built or provided as part
74+
* of an application - to control the routing of requests to handler objects. Default is
75+
* {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} and
76+
* {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}.
77+
* HandlerMapping objects can be defined as beans in the servlet's application context,
78+
* implementing the HandlerMapping interface, overriding the default HandlerMapping if
79+
* present. HandlerMappings can be given any bean name (they are tested by type).
7780
*
78-
* <li>It can use any {@link HandlerAdapter}; this allows for using any handler interface. Default adapters are {@link
79-
* org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter}, {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter},
80-
* for Spring's {@link org.springframework.web.HttpRequestHandler} and {@link org.springframework.web.servlet.mvc.Controller}
81-
* interfaces, respectively. A default {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
82-
* will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the
83-
* default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type).
81+
* <li>It can use any {@link HandlerAdapter}; this allows for using any handler interface.
82+
* Default adapters are {@link org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter},
83+
* {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}, for Spring's
84+
* {@link org.springframework.web.HttpRequestHandler} and
85+
* {@link org.springframework.web.servlet.mvc.Controller} interfaces, respectively. A default
86+
* {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
87+
* will be registered as well. HandlerAdapter objects can be added as beans in the
88+
* application context, overriding the default HandlerAdapters. Like HandlerMappings,
89+
* HandlerAdapters can be given any bean name (they are tested by type).
8490
*
85-
* <li>The dispatcher's exception resolution strategy can be specified via a {@link HandlerExceptionResolver}, for
86-
* example mapping certain exceptions to error pages. Default are
91+
* <li>The dispatcher's exception resolution strategy can be specified via a
92+
* {@link HandlerExceptionResolver}, for example mapping certain exceptions to error pages.
93+
* Default are
8794
* {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver},
8895
* {@link org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver}, and
89-
* {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}. These HandlerExceptionResolvers can be overridden
90-
* through the application context. HandlerExceptionResolver can be given any bean name (they are tested by type).
96+
* {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}.
97+
* These HandlerExceptionResolvers can be overridden through the application context.
98+
* HandlerExceptionResolver can be given any bean name (they are tested by type).
9199
*
92-
* <li>Its view resolution strategy can be specified via a {@link ViewResolver} implementation, resolving symbolic view
93-
* names into View objects. Default is {@link org.springframework.web.servlet.view.InternalResourceViewResolver}.
94-
* ViewResolver objects can be added as beans in the application context, overriding the default ViewResolver.
95-
* ViewResolvers can be given any bean name (they are tested by type).
100+
* <li>Its view resolution strategy can be specified via a {@link ViewResolver}
101+
* implementation, resolving symbolic view names into View objects. Default is
102+
* {@link org.springframework.web.servlet.view.InternalResourceViewResolver}.
103+
* ViewResolver objects can be added as beans in the application context, overriding the
104+
* default ViewResolver. ViewResolvers can be given any bean name (they are tested by type).
96105
*
97-
* <li>If a {@link View} or view name is not supplied by the user, then the configured {@link
98-
* RequestToViewNameTranslator} will translate the current request into a view name. The corresponding bean name is
99-
* "viewNameTranslator"; the default is {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}.
106+
* <li>If a {@link View} or view name is not supplied by the user, then the configured
107+
* {@link RequestToViewNameTranslator} will translate the current request into a view name.
108+
* The corresponding bean name is "viewNameTranslator"; the default is
109+
* {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}.
100110
*
101-
* <li>The dispatcher's strategy for resolving multipart requests is determined by a {@link
102-
* org.springframework.web.multipart.MultipartResolver} implementation. Implementations for Jakarta Commons FileUpload
103-
* and Jason Hunter's COS are included; the typical choise is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}.
111+
* <li>The dispatcher's strategy for resolving multipart requests is determined by a
112+
* {@link org.springframework.web.multipart.MultipartResolver} implementation.
113+
* Implementations for Apache Commons FileUpload and Servlet 3 are included; the typical
114+
* choice is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}.
104115
* The MultipartResolver bean name is "multipartResolver"; default is none.
105116
*
106-
* <li>Its locale resolution strategy is determined by a {@link LocaleResolver}. Out-of-the-box implementations work via
107-
* HTTP accept header, cookie, or session. The LocaleResolver bean name is "localeResolver"; default is {@link
108-
* org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
117+
* <li>Its locale resolution strategy is determined by a {@link LocaleResolver}.
118+
* Out-of-the-box implementations work via HTTP accept header, cookie, or session.
119+
* The LocaleResolver bean name is "localeResolver"; default is
120+
* {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
109121
*
110-
* <li>Its theme resolution strategy is determined by a {@link ThemeResolver}. Implementations for a fixed theme and for
111-
* cookie and session storage are included. The ThemeResolver bean name is "themeResolver"; default is {@link
112-
* org.springframework.web.servlet.theme.FixedThemeResolver}. </ul>
122+
* <li>Its theme resolution strategy is determined by a {@link ThemeResolver}.
123+
* Implementations for a fixed theme and for cookie and session storage are included.
124+
* The ThemeResolver bean name is "themeResolver"; default is
125+
* {@link org.springframework.web.servlet.theme.FixedThemeResolver}.
126+
* </ul>
113127
*
114-
* <p><b>NOTE: The {@code @RequestMapping} annotation will only be processed if a corresponding
115-
* {@code HandlerMapping} (for type level annotations) and/or {@code HandlerAdapter} (for method level
116-
* annotations) is present in the dispatcher.</b> This is the case by default. However, if you are defining custom
117-
* {@code HandlerMappings} or {@code HandlerAdapters}, then you need to make sure that a corresponding custom
118-
* {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter} is defined as well -
119-
* provided that you intend to use {@code @RequestMapping}.
128+
* <p><b>NOTE: The {@code @RequestMapping} annotation will only be processed if a
129+
* corresponding {@code HandlerMapping} (for type-level annotations) and/or
130+
* {@code HandlerAdapter} (for method-level annotations) is present in the dispatcher.</b>
131+
* This is the case by default. However, if you are defining custom {@code HandlerMappings}
132+
* or {@code HandlerAdapters}, then you need to make sure that a corresponding custom
133+
* {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter}
134+
* is defined as well - provided that you intend to use {@code @RequestMapping}.
120135
*
121-
* <p><b>A web application can define any number of DispatcherServlets.</b> Each servlet will operate in its own
122-
* namespace, loading its own application context with mappings, handlers, etc. Only the root application context as
123-
* loaded by {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared.
136+
* <p><b>A web application can define any number of DispatcherServlets.</b>
137+
* Each servlet will operate in its own namespace, loading its own application context
138+
* with mappings, handlers, etc. Only the root application context as loaded by
139+
* {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared.
124140
*
125141
* <p>As of Spring 3.1, {@code DispatcherServlet} may now be injected with a web
126142
* application context, rather than creating its own internally. This is useful in Servlet
127-
* 3.0+ environments, which support programmatic registration of servlet instances. See
128-
* {@link #DispatcherServlet(WebApplicationContext)} Javadoc for details.
143+
* 3.0+ environments, which support programmatic registration of servlet instances.
144+
* See the {@link #DispatcherServlet(WebApplicationContext)} javadoc for details.
129145
*
130146
* @author Rod Johnson
131147
* @author Juergen Hoeller
@@ -851,12 +867,11 @@ protected void doService(HttpServletRequest request, HttpServletResponse respons
851867
doDispatch(request, response);
852868
}
853869
finally {
854-
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
855-
return;
856-
}
857-
// Restore the original attribute snapshot, in case of an include.
858-
if (attributesSnapshot != null) {
859-
restoreAttributesAfterInclude(request, attributesSnapshot);
870+
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
871+
// Restore the original attribute snapshot, in case of an include.
872+
if (attributesSnapshot != null) {
873+
restoreAttributesAfterInclude(request, attributesSnapshot);
874+
}
860875
}
861876
}
862877
}
@@ -885,7 +900,7 @@ protected void doDispatch(HttpServletRequest request, HttpServletResponse respon
885900

886901
try {
887902
processedRequest = checkMultipart(request);
888-
multipartRequestParsed = processedRequest != request;
903+
multipartRequestParsed = (processedRequest != request);
889904

890905
// Determine handler for the current request.
891906
mappedHandler = getHandler(processedRequest, false);
@@ -914,14 +929,11 @@ protected void doDispatch(HttpServletRequest request, HttpServletResponse respon
914929
return;
915930
}
916931

917-
try {
918-
// Actually invoke the handler.
919-
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
920-
}
921-
finally {
922-
if (asyncManager.isConcurrentHandlingStarted()) {
923-
return;
924-
}
932+
// Actually invoke the handler.
933+
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
934+
935+
if (asyncManager.isConcurrentHandlingStarted()) {
936+
return;
925937
}
926938

927939
applyDefaultViewName(request, mv);
@@ -941,12 +953,15 @@ protected void doDispatch(HttpServletRequest request, HttpServletResponse respon
941953
finally {
942954
if (asyncManager.isConcurrentHandlingStarted()) {
943955
// Instead of postHandle and afterCompletion
944-
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
945-
return;
956+
if (mappedHandler != null) {
957+
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
958+
}
946959
}
947-
// Clean up any resources used by a multipart request.
948-
if (multipartRequestParsed) {
949-
cleanupMultipart(processedRequest);
960+
else {
961+
// Clean up any resources used by a multipart request.
962+
if (multipartRequestParsed) {
963+
cleanupMultipart(processedRequest);
964+
}
950965
}
951966
}
952967
}
@@ -1255,7 +1270,7 @@ private void triggerAfterCompletion(HttpServletRequest request, HttpServletRespo
12551270
}
12561271

12571272
private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response,
1258-
HandlerExecutionChain mappedHandler, Error error) throws Exception, ServletException {
1273+
HandlerExecutionChain mappedHandler, Error error) throws Exception {
12591274

12601275
ServletException ex = new NestedServletException("Handler processing failed", error);
12611276
if (mappedHandler != null) {

0 commit comments

Comments
 (0)