View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.web.servlet;
18  
19  import java.io.IOException;
20  import java.security.Principal;
21  import java.util.ArrayList;
22  import java.util.concurrent.Callable;
23  import javax.servlet.ServletContext;
24  import javax.servlet.ServletException;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  import javax.servlet.http.HttpServletResponseWrapper;
28  
29  import org.springframework.beans.BeanUtils;
30  import org.springframework.context.ApplicationContext;
31  import org.springframework.context.ApplicationContextAware;
32  import org.springframework.context.ApplicationContextException;
33  import org.springframework.context.ApplicationContextInitializer;
34  import org.springframework.context.ApplicationListener;
35  import org.springframework.context.ConfigurableApplicationContext;
36  import org.springframework.context.event.ContextRefreshedEvent;
37  import org.springframework.context.event.SourceFilteringListener;
38  import org.springframework.context.i18n.LocaleContext;
39  import org.springframework.context.i18n.LocaleContextHolder;
40  import org.springframework.context.i18n.SimpleLocaleContext;
41  import org.springframework.core.GenericTypeResolver;
42  import org.springframework.core.annotation.AnnotationAwareOrderComparator;
43  import org.springframework.core.env.ConfigurableEnvironment;
44  import org.springframework.util.Assert;
45  import org.springframework.util.ClassUtils;
46  import org.springframework.util.ObjectUtils;
47  import org.springframework.util.StringUtils;
48  import org.springframework.web.bind.annotation.RequestMethod;
49  import org.springframework.web.context.ConfigurableWebApplicationContext;
50  import org.springframework.web.context.ConfigurableWebEnvironment;
51  import org.springframework.web.context.ContextLoader;
52  import org.springframework.web.context.WebApplicationContext;
53  import org.springframework.web.context.request.NativeWebRequest;
54  import org.springframework.web.context.request.RequestAttributes;
55  import org.springframework.web.context.request.RequestContextHolder;
56  import org.springframework.web.context.request.ServletRequestAttributes;
57  import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
58  import org.springframework.web.context.request.async.WebAsyncManager;
59  import org.springframework.web.context.request.async.WebAsyncUtils;
60  import org.springframework.web.context.support.ServletRequestHandledEvent;
61  import org.springframework.web.context.support.WebApplicationContextUtils;
62  import org.springframework.web.context.support.XmlWebApplicationContext;
63  import org.springframework.web.util.NestedServletException;
64  import org.springframework.web.util.WebUtils;
65  
66  /**
67   * Base servlet for Spring's web framework. Provides integration with
68   * a Spring application context, in a JavaBean-based overall solution.
69   *
70   * <p>This class offers the following functionality:
71   * <ul>
72   * <li>Manages a {@link org.springframework.web.context.WebApplicationContext
73   * WebApplicationContext} instance per servlet. The servlet's configuration is determined
74   * by beans in the servlet's namespace.
75   * <li>Publishes events on request processing, whether or not a request is
76   * successfully handled.
77   * </ul>
78   *
79   * <p>Subclasses must implement {@link #doService} to handle requests. Because this extends
80   * {@link HttpServletBean} rather than HttpServlet directly, bean properties are
81   * automatically mapped onto it. Subclasses can override {@link #initFrameworkServlet()}
82   * for custom initialization.
83   *
84   * <p>Detects a "contextClass" parameter at the servlet init-param level,
85   * falling back to the default context class,
86   * {@link org.springframework.web.context.support.XmlWebApplicationContext
87   * XmlWebApplicationContext}, if not found. Note that, with the default
88   * {@code FrameworkServlet}, a custom context class needs to implement the
89   * {@link org.springframework.web.context.ConfigurableWebApplicationContext
90   * ConfigurableWebApplicationContext} SPI.
91   *
92   * <p>Accepts an optional "contextInitializerClasses" servlet init-param that
93   * specifies one or more {@link org.springframework.context.ApplicationContextInitializer
94   * ApplicationContextInitializer} classes. The managed web application context will be
95   * delegated to these initializers, allowing for additional programmatic configuration,
96   * e.g. adding property sources or activating profiles against the {@linkplain
97   * org.springframework.context.ConfigurableApplicationContext#getEnvironment() context's
98   * environment}. See also {@link org.springframework.web.context.ContextLoader} which
99   * supports a "contextInitializerClasses" context-param with identical semantics for
100  * the "root" web application context.
101  *
102  * <p>Passes a "contextConfigLocation" servlet init-param to the context instance,
103  * parsing it into potentially multiple file paths which can be separated by any
104  * number of commas and spaces, like "test-servlet.xml, myServlet.xml".
105  * If not explicitly specified, the context implementation is supposed to build a
106  * default location from the namespace of the servlet.
107  *
108  * <p>Note: In case of multiple config locations, later bean definitions will
109  * override ones defined in earlier loaded files, at least when using Spring's
110  * default ApplicationContext implementation. This can be leveraged to
111  * deliberately override certain bean definitions via an extra XML file.
112  *
113  * <p>The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a
114  * servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location
115  * with XmlWebApplicationContext). The namespace can also be set explicitly via
116  * the "namespace" servlet init-param.
117  *
118  * <p>As of Spring 3.1, {@code FrameworkServlet} may now be injected with a web
119  * application context, rather than creating its own internally. This is useful in Servlet
120  * 3.0+ environments, which support programmatic registration of servlet instances. See
121  * {@link #FrameworkServlet(WebApplicationContext)} Javadoc for details.
122  *
123  * @author Rod Johnson
124  * @author Juergen Hoeller
125  * @author Sam Brannen
126  * @author Chris Beams
127  * @author Rossen Stoyanchev
128  * @author Phillip Webb
129  * @see #doService
130  * @see #setContextClass
131  * @see #setContextConfigLocation
132  * @see #setContextInitializerClasses
133  * @see #setNamespace
134  */
135 @SuppressWarnings("serial")
136 public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
137 
138 	/**
139 	 * Suffix for WebApplicationContext namespaces. If a servlet of this class is
140 	 * given the name "test" in a context, the namespace used by the servlet will
141 	 * resolve to "test-servlet".
142 	 */
143 	public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
144 
145 	/**
146 	 * Default context class for FrameworkServlet.
147 	 * @see org.springframework.web.context.support.XmlWebApplicationContext
148 	 */
149 	public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
150 
151 	/**
152 	 * Prefix for the ServletContext attribute for the WebApplicationContext.
153 	 * The completion is the servlet name.
154 	 */
155 	public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";
156 
157 	/**
158 	 * Any number of these characters are considered delimiters between
159 	 * multiple values in a single init-param String value.
160 	 */
161 	private static final String INIT_PARAM_DELIMITERS = ",; \t\n";
162 
163 
164 	/** Checking for Servlet 3.0+ HttpServletResponse.getStatus() */
165 	private static final boolean responseGetStatusAvailable =
166 			ClassUtils.hasMethod(HttpServletResponse.class, "getStatus");
167 
168 
169 	/** ServletContext attribute to find the WebApplicationContext in */
170 	private String contextAttribute;
171 
172 	/** WebApplicationContext implementation class to create */
173 	private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
174 
175 	/** WebApplicationContext id to assign */
176 	private String contextId;
177 
178 	/** Namespace for this servlet */
179 	private String namespace;
180 
181 	/** Explicit context config location */
182 	private String contextConfigLocation;
183 
184 	/** Actual ApplicationContextInitializer instances to apply to the context */
185 	private final ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
186 			new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
187 
188 	/** Comma-delimited ApplicationContextInitializer class names set through init param */
189 	private String contextInitializerClasses;
190 
191 	/** Should we publish the context as a ServletContext attribute? */
192 	private boolean publishContext = true;
193 
194 	/** Should we publish a ServletRequestHandledEvent at the end of each request? */
195 	private boolean publishEvents = true;
196 
197 	/** Expose LocaleContext and RequestAttributes as inheritable for child threads? */
198 	private boolean threadContextInheritable = false;
199 
200 	/** Should we dispatch an HTTP OPTIONS request to {@link #doService}? */
201 	private boolean dispatchOptionsRequest = false;
202 
203 	/** Should we dispatch an HTTP TRACE request to {@link #doService}? */
204 	private boolean dispatchTraceRequest = false;
205 
206 	/** WebApplicationContext for this servlet */
207 	private WebApplicationContext webApplicationContext;
208 
209 	/** If the WebApplicationContext was injected via {@link #setApplicationContext} */
210 	private boolean webApplicationContextInjected = false;
211 
212 	/** Flag used to detect whether onRefresh has already been called */
213 	private boolean refreshEventReceived = false;
214 
215 
216 	/**
217 	 * Create a new {@code FrameworkServlet} that will create its own internal web
218 	 * application context based on defaults and values provided through servlet
219 	 * init-params. Typically used in Servlet 2.5 or earlier environments, where the only
220 	 * option for servlet registration is through {@code web.xml} which requires the use
221 	 * of a no-arg constructor.
222 	 * <p>Calling {@link #setContextConfigLocation} (init-param 'contextConfigLocation')
223 	 * will dictate which XML files will be loaded by the
224 	 * {@linkplain #DEFAULT_CONTEXT_CLASS default XmlWebApplicationContext}
225 	 * <p>Calling {@link #setContextClass} (init-param 'contextClass') overrides the
226 	 * default {@code XmlWebApplicationContext} and allows for specifying an alternative class,
227 	 * such as {@code AnnotationConfigWebApplicationContext}.
228 	 * <p>Calling {@link #setContextInitializerClasses} (init-param 'contextInitializerClasses')
229 	 * indicates which {@link ApplicationContextInitializer} classes should be used to
230 	 * further configure the internal application context prior to refresh().
231 	 * @see #FrameworkServlet(WebApplicationContext)
232 	 */
233 	public FrameworkServlet() {
234 	}
235 
236 	/**
237 	 * Create a new {@code FrameworkServlet} with the given web application context. This
238 	 * constructor is useful in Servlet 3.0+ environments where instance-based registration
239 	 * of servlets is possible through the {@link ServletContext#addServlet} API.
240 	 * <p>Using this constructor indicates that the following properties / init-params
241 	 * will be ignored:
242 	 * <ul>
243 	 * <li>{@link #setContextClass(Class)} / 'contextClass'</li>
244 	 * <li>{@link #setContextConfigLocation(String)} / 'contextConfigLocation'</li>
245 	 * <li>{@link #setContextAttribute(String)} / 'contextAttribute'</li>
246 	 * <li>{@link #setNamespace(String)} / 'namespace'</li>
247 	 * </ul>
248 	 * <p>The given web application context may or may not yet be {@linkplain
249 	 * ConfigurableApplicationContext#refresh() refreshed}. If it (a) is an implementation
250 	 * of {@link ConfigurableWebApplicationContext} and (b) has <strong>not</strong>
251 	 * already been refreshed (the recommended approach), then the following will occur:
252 	 * <ul>
253 	 * <li>If the given context does not already have a {@linkplain
254 	 * ConfigurableApplicationContext#setParent parent}, the root application context
255 	 * will be set as the parent.</li>
256 	 * <li>If the given context has not already been assigned an {@linkplain
257 	 * ConfigurableApplicationContext#setId id}, one will be assigned to it</li>
258 	 * <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to
259 	 * the application context</li>
260 	 * <li>{@link #postProcessWebApplicationContext} will be called</li>
261 	 * <li>Any {@link ApplicationContextInitializer}s specified through the
262 	 * "contextInitializerClasses" init-param or through the {@link
263 	 * #setContextInitializers} property will be applied.</li>
264 	 * <li>{@link ConfigurableApplicationContext#refresh refresh()} will be called</li>
265 	 * </ul>
266 	 * If the context has already been refreshed or does not implement
267 	 * {@code ConfigurableWebApplicationContext}, none of the above will occur under the
268 	 * assumption that the user has performed these actions (or not) per his or her
269 	 * specific needs.
270 	 * <p>See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
271 	 * @param webApplicationContext the context to use
272 	 * @see #initWebApplicationContext
273 	 * @see #configureAndRefreshWebApplicationContext
274 	 * @see org.springframework.web.WebApplicationInitializer
275 	 */
276 	public FrameworkServlet(WebApplicationContext webApplicationContext) {
277 		this.webApplicationContext = webApplicationContext;
278 	}
279 
280 
281 	/**
282 	 * Set the name of the ServletContext attribute which should be used to retrieve the
283 	 * {@link WebApplicationContext} that this servlet is supposed to use.
284 	 */
285 	public void setContextAttribute(String contextAttribute) {
286 		this.contextAttribute = contextAttribute;
287 	}
288 
289 	/**
290 	 * Return the name of the ServletContext attribute which should be used to retrieve the
291 	 * {@link WebApplicationContext} that this servlet is supposed to use.
292 	 */
293 	public String getContextAttribute() {
294 		return this.contextAttribute;
295 	}
296 
297 	/**
298 	 * Set a custom context class. This class must be of type
299 	 * {@link org.springframework.web.context.WebApplicationContext}.
300 	 * <p>When using the default FrameworkServlet implementation,
301 	 * the context class must also implement the
302 	 * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
303 	 * interface.
304 	 * @see #createWebApplicationContext
305 	 */
306 	public void setContextClass(Class<?> contextClass) {
307 		this.contextClass = contextClass;
308 	}
309 
310 	/**
311 	 * Return the custom context class.
312 	 */
313 	public Class<?> getContextClass() {
314 		return this.contextClass;
315 	}
316 
317 	/**
318 	 * Specify a custom WebApplicationContext id,
319 	 * to be used as serialization id for the underlying BeanFactory.
320 	 */
321 	public void setContextId(String contextId) {
322 		this.contextId = contextId;
323 	}
324 
325 	/**
326 	 * Return the custom WebApplicationContext id, if any.
327 	 */
328 	public String getContextId() {
329 		return this.contextId;
330 	}
331 
332 	/**
333 	 * Set a custom namespace for this servlet,
334 	 * to be used for building a default context config location.
335 	 */
336 	public void setNamespace(String namespace) {
337 		this.namespace = namespace;
338 	}
339 
340 	/**
341 	 * Return the namespace for this servlet, falling back to default scheme if
342 	 * no custom namespace was set: e.g. "test-servlet" for a servlet named "test".
343 	 */
344 	public String getNamespace() {
345 		return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);
346 	}
347 
348 	/**
349 	 * Set the context config location explicitly, instead of relying on the default
350 	 * location built from the namespace. This location string can consist of
351 	 * multiple locations separated by any number of commas and spaces.
352 	 */
353 	public void setContextConfigLocation(String contextConfigLocation) {
354 		this.contextConfigLocation = contextConfigLocation;
355 	}
356 
357 	/**
358 	 * Return the explicit context config location, if any.
359 	 */
360 	public String getContextConfigLocation() {
361 		return this.contextConfigLocation;
362 	}
363 
364 	/**
365 	 * Specify which {@link ApplicationContextInitializer} instances should be used
366 	 * to initialize the application context used by this {@code FrameworkServlet}.
367 	 * @see #configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext)
368 	 * @see #applyInitializers(ConfigurableApplicationContext)
369 	 */
370 	@SuppressWarnings("unchecked")
371 	public void setContextInitializers(ApplicationContextInitializer<? extends ConfigurableApplicationContext>... contextInitializers) {
372 		for (ApplicationContextInitializer<? extends ConfigurableApplicationContext> initializer : contextInitializers) {
373 			this.contextInitializers.add((ApplicationContextInitializer<ConfigurableApplicationContext>) initializer);
374 		}
375 	}
376 
377 	/**
378 	 * Specify the set of fully-qualified {@link ApplicationContextInitializer} class
379 	 * names, per the optional "contextInitializerClasses" servlet init-param.
380 	 * @see #configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext)
381 	 * @see #applyInitializers(ConfigurableApplicationContext)
382 	 */
383 	public void setContextInitializerClasses(String contextInitializerClasses) {
384 		this.contextInitializerClasses = contextInitializerClasses;
385 	}
386 
387 	/**
388 	 * Set whether to publish this servlet's context as a ServletContext attribute,
389 	 * available to all objects in the web container. Default is "true".
390 	 * <p>This is especially handy during testing, although it is debatable whether
391 	 * it's good practice to let other application objects access the context this way.
392 	 */
393 	public void setPublishContext(boolean publishContext) {
394 		this.publishContext = publishContext;
395 	}
396 
397 	/**
398 	 * Set whether this servlet should publish a ServletRequestHandledEvent at the end
399 	 * of each request. Default is "true"; can be turned off for a slight performance
400 	 * improvement, provided that no ApplicationListeners rely on such events.
401 	 * @see org.springframework.web.context.support.ServletRequestHandledEvent
402 	 */
403 	public void setPublishEvents(boolean publishEvents) {
404 		this.publishEvents = publishEvents;
405 	}
406 
407 	/**
408 	 * Set whether to expose the LocaleContext and RequestAttributes as inheritable
409 	 * for child threads (using an {@link java.lang.InheritableThreadLocal}).
410 	 * <p>Default is "false", to avoid side effects on spawned background threads.
411 	 * Switch this to "true" to enable inheritance for custom child threads which
412 	 * are spawned during request processing and only used for this request
413 	 * (that is, ending after their initial task, without reuse of the thread).
414 	 * <p><b>WARNING:</b> Do not use inheritance for child threads if you are
415 	 * accessing a thread pool which is configured to potentially add new threads
416 	 * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
417 	 * since this will expose the inherited context to such a pooled thread.
418 	 */
419 	public void setThreadContextInheritable(boolean threadContextInheritable) {
420 		this.threadContextInheritable = threadContextInheritable;
421 	}
422 
423 	/**
424 	 * Set whether this servlet should dispatch an HTTP OPTIONS request to
425 	 * the {@link #doService} method.
426 	 * <p>Default is "false", applying {@link javax.servlet.http.HttpServlet}'s
427 	 * default behavior (i.e. enumerating all standard HTTP request methods
428 	 * as a response to the OPTIONS request).
429 	 * <p>Turn this flag on if you prefer OPTIONS requests to go through the
430 	 * regular dispatching chain, just like other HTTP requests. This usually
431 	 * means that your controllers will receive those requests; make sure
432 	 * that those endpoints are actually able to handle an OPTIONS request.
433 	 * <p>Note that HttpServlet's default OPTIONS processing will be applied
434 	 * in any case if your controllers happen to not set the 'Allow' header
435 	 * (as required for an OPTIONS response).
436 	 */
437 	public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {
438 		this.dispatchOptionsRequest = dispatchOptionsRequest;
439 	}
440 
441 	/**
442 	 * Set whether this servlet should dispatch an HTTP TRACE request to
443 	 * the {@link #doService} method.
444 	 * <p>Default is "false", applying {@link javax.servlet.http.HttpServlet}'s
445 	 * default behavior (i.e. reflecting the message received back to the client).
446 	 * <p>Turn this flag on if you prefer TRACE requests to go through the
447 	 * regular dispatching chain, just like other HTTP requests. This usually
448 	 * means that your controllers will receive those requests; make sure
449 	 * that those endpoints are actually able to handle a TRACE request.
450 	 * <p>Note that HttpServlet's default TRACE processing will be applied
451 	 * in any case if your controllers happen to not generate a response
452 	 * of content type 'message/http' (as required for a TRACE response).
453 	 */
454 	public void setDispatchTraceRequest(boolean dispatchTraceRequest) {
455 		this.dispatchTraceRequest = dispatchTraceRequest;
456 	}
457 
458 	/**
459 	 * Called by Spring via {@link ApplicationContextAware} to inject the current
460 	 * application context. This method allows FrameworkServlets to be registered as
461 	 * Spring beans inside an existing {@link WebApplicationContext} rather than
462 	 * {@link #findWebApplicationContext() finding} a
463 	 * {@link org.springframework.web.context.ContextLoaderListener bootstrapped} context.
464 	 * <p>Primarily added to support use in embedded servlet containers.
465 	 * @since 4.0
466 	 */
467 	@Override
468 	public void setApplicationContext(ApplicationContext applicationContext) {
469 		if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
470 			this.webApplicationContext = (WebApplicationContext) applicationContext;
471 			this.webApplicationContextInjected = true;
472 		}
473 	}
474 
475 
476 	/**
477 	 * Overridden method of {@link HttpServletBean}, invoked after any bean properties
478 	 * have been set. Creates this servlet's WebApplicationContext.
479 	 */
480 	@Override
481 	protected final void initServletBean() throws ServletException {
482 		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
483 		if (this.logger.isInfoEnabled()) {
484 			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
485 		}
486 		long startTime = System.currentTimeMillis();
487 
488 		try {
489 			this.webApplicationContext = initWebApplicationContext();
490 			initFrameworkServlet();
491 		}
492 		catch (ServletException ex) {
493 			this.logger.error("Context initialization failed", ex);
494 			throw ex;
495 		}
496 		catch (RuntimeException ex) {
497 			this.logger.error("Context initialization failed", ex);
498 			throw ex;
499 		}
500 
501 		if (this.logger.isInfoEnabled()) {
502 			long elapsedTime = System.currentTimeMillis() - startTime;
503 			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
504 					elapsedTime + " ms");
505 		}
506 	}
507 
508 	/**
509 	 * Initialize and publish the WebApplicationContext for this servlet.
510 	 * <p>Delegates to {@link #createWebApplicationContext} for actual creation
511 	 * of the context. Can be overridden in subclasses.
512 	 * @return the WebApplicationContext instance
513 	 * @see #FrameworkServlet(WebApplicationContext)
514 	 * @see #setContextClass
515 	 * @see #setContextConfigLocation
516 	 */
517 	protected WebApplicationContext initWebApplicationContext() {
518 		WebApplicationContext rootContext =
519 				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
520 		WebApplicationContext wac = null;
521 
522 		if (this.webApplicationContext != null) {
523 			// A context instance was injected at construction time -> use it
524 			wac = this.webApplicationContext;
525 			if (wac instanceof ConfigurableWebApplicationContext) {
526 				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
527 				if (!cwac.isActive()) {
528 					// The context has not yet been refreshed -> provide services such as
529 					// setting the parent context, setting the application context id, etc
530 					if (cwac.getParent() == null) {
531 						// The context instance was injected without an explicit parent -> set
532 						// the root application context (if any; may be null) as the parent
533 						cwac.setParent(rootContext);
534 					}
535 					configureAndRefreshWebApplicationContext(cwac);
536 				}
537 			}
538 		}
539 		if (wac == null) {
540 			// No context instance was injected at construction time -> see if one
541 			// has been registered in the servlet context. If one exists, it is assumed
542 			// that the parent context (if any) has already been set and that the
543 			// user has performed any initialization such as setting the context id
544 			wac = findWebApplicationContext();
545 		}
546 		if (wac == null) {
547 			// No context instance is defined for this servlet -> create a local one
548 			wac = createWebApplicationContext(rootContext);
549 		}
550 
551 		if (!this.refreshEventReceived) {
552 			// Either the context is not a ConfigurableApplicationContext with refresh
553 			// support or the context injected at construction time had already been
554 			// refreshed -> trigger initial onRefresh manually here.
555 			onRefresh(wac);
556 		}
557 
558 		if (this.publishContext) {
559 			// Publish the context as a servlet context attribute.
560 			String attrName = getServletContextAttributeName();
561 			getServletContext().setAttribute(attrName, wac);
562 			if (this.logger.isDebugEnabled()) {
563 				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
564 						"' as ServletContext attribute with name [" + attrName + "]");
565 			}
566 		}
567 
568 		return wac;
569 	}
570 
571 	/**
572 	 * Retrieve a {@code WebApplicationContext} from the {@code ServletContext}
573 	 * attribute with the {@link #setContextAttribute configured name}. The
574 	 * {@code WebApplicationContext} must have already been loaded and stored in the
575 	 * {@code ServletContext} before this servlet gets initialized (or invoked).
576 	 * <p>Subclasses may override this method to provide a different
577 	 * {@code WebApplicationContext} retrieval strategy.
578 	 * @return the WebApplicationContext for this servlet, or {@code null} if not found
579 	 * @see #getContextAttribute()
580 	 */
581 	protected WebApplicationContext findWebApplicationContext() {
582 		String attrName = getContextAttribute();
583 		if (attrName == null) {
584 			return null;
585 		}
586 		WebApplicationContext wac =
587 				WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
588 		if (wac == null) {
589 			throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
590 		}
591 		return wac;
592 	}
593 
594 	/**
595 	 * Instantiate the WebApplicationContext for this servlet, either a default
596 	 * {@link org.springframework.web.context.support.XmlWebApplicationContext}
597 	 * or a {@link #setContextClass custom context class}, if set.
598 	 * <p>This implementation expects custom contexts to implement the
599 	 * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
600 	 * interface. Can be overridden in subclasses.
601 	 * <p>Do not forget to register this servlet instance as application listener on the
602 	 * created context (for triggering its {@link #onRefresh callback}, and to call
603 	 * {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
604 	 * before returning the context instance.
605 	 * @param parent the parent ApplicationContext to use, or {@code null} if none
606 	 * @return the WebApplicationContext for this servlet
607 	 * @see org.springframework.web.context.support.XmlWebApplicationContext
608 	 */
609 	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
610 		Class<?> contextClass = getContextClass();
611 		if (this.logger.isDebugEnabled()) {
612 			this.logger.debug("Servlet with name '" + getServletName() +
613 					"' will try to create custom WebApplicationContext context of class '" +
614 					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
615 		}
616 		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
617 			throw new ApplicationContextException(
618 					"Fatal initialization error in servlet with name '" + getServletName() +
619 					"': custom WebApplicationContext class [" + contextClass.getName() +
620 					"] is not of type ConfigurableWebApplicationContext");
621 		}
622 		ConfigurableWebApplicationContext wac =
623 				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
624 
625 		wac.setEnvironment(getEnvironment());
626 		wac.setParent(parent);
627 		wac.setConfigLocation(getContextConfigLocation());
628 
629 		configureAndRefreshWebApplicationContext(wac);
630 
631 		return wac;
632 	}
633 
634 	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
635 		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
636 			// The application context id is still set to its original default value
637 			// -> assign a more useful id based on available information
638 			if (this.contextId != null) {
639 				wac.setId(this.contextId);
640 			}
641 			else {
642 				// Generate default id...
643 				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
644 						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());
645 			}
646 		}
647 
648 		wac.setServletContext(getServletContext());
649 		wac.setServletConfig(getServletConfig());
650 		wac.setNamespace(getNamespace());
651 		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
652 
653 		// The wac environment's #initPropertySources will be called in any case when the context
654 		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
655 		// use in any post-processing or initialization that occurs below prior to #refresh
656 		ConfigurableEnvironment env = wac.getEnvironment();
657 		if (env instanceof ConfigurableWebEnvironment) {
658 			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
659 		}
660 
661 		postProcessWebApplicationContext(wac);
662 		applyInitializers(wac);
663 		wac.refresh();
664 	}
665 
666 	/**
667 	 * Instantiate the WebApplicationContext for this servlet, either a default
668 	 * {@link org.springframework.web.context.support.XmlWebApplicationContext}
669 	 * or a {@link #setContextClass custom context class}, if set.
670 	 * Delegates to #createWebApplicationContext(ApplicationContext).
671 	 * @param parent the parent WebApplicationContext to use, or {@code null} if none
672 	 * @return the WebApplicationContext for this servlet
673 	 * @see org.springframework.web.context.support.XmlWebApplicationContext
674 	 * @see #createWebApplicationContext(ApplicationContext)
675 	 */
676 	protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
677 		return createWebApplicationContext((ApplicationContext) parent);
678 	}
679 
680 	/**
681 	 * Post-process the given WebApplicationContext before it is refreshed
682 	 * and activated as context for this servlet.
683 	 * <p>The default implementation is empty. {@code refresh()} will
684 	 * be called automatically after this method returns.
685 	 * <p>Note that this method is designed to allow subclasses to modify the application
686 	 * context, while {@link #initWebApplicationContext} is designed to allow
687 	 * end-users to modify the context through the use of
688 	 * {@link ApplicationContextInitializer}s.
689 	 * @param wac the configured WebApplicationContext (not refreshed yet)
690 	 * @see #createWebApplicationContext
691 	 * @see #initWebApplicationContext
692 	 * @see ConfigurableWebApplicationContext#refresh()
693 	 */
694 	protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) {
695 	}
696 
697 	/**
698 	 * Delegate the WebApplicationContext before it is refreshed to any
699 	 * {@link ApplicationContextInitializer} instances specified by the
700 	 * "contextInitializerClasses" servlet init-param.
701 	 * <p>See also {@link #postProcessWebApplicationContext}, which is designed to allow
702 	 * subclasses (as opposed to end-users) to modify the application context, and is
703 	 * called immediately before this method.
704 	 * @param wac the configured WebApplicationContext (not refreshed yet)
705 	 * @see #createWebApplicationContext
706 	 * @see #postProcessWebApplicationContext
707 	 * @see ConfigurableApplicationContext#refresh()
708 	 */
709 	protected void applyInitializers(ConfigurableApplicationContext wac) {
710 		String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
711 		if (globalClassNames != null) {
712 			for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
713 				this.contextInitializers.add(loadInitializer(className, wac));
714 			}
715 		}
716 
717 		if (this.contextInitializerClasses != null) {
718 			for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
719 				this.contextInitializers.add(loadInitializer(className, wac));
720 			}
721 		}
722 
723 		AnnotationAwareOrderComparator.sort(this.contextInitializers);
724 		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
725 			initializer.initialize(wac);
726 		}
727 	}
728 
729 	@SuppressWarnings("unchecked")
730 	private ApplicationContextInitializer<ConfigurableApplicationContext> loadInitializer(
731 			String className, ConfigurableApplicationContext wac) {
732 		try {
733 			Class<?> initializerClass = ClassUtils.forName(className, wac.getClassLoader());
734 			Class<?> initializerContextClass =
735 					GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
736 			if (initializerContextClass != null) {
737 				Assert.isAssignable(initializerContextClass, wac.getClass(), String.format(
738 						"Could not add context initializer [%s] since its generic parameter [%s] " +
739 						"is not assignable from the type of application context used by this " +
740 						"framework servlet [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
741 						wac.getClass().getName()));
742 			}
743 			return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class);
744 		}
745 		catch (Exception ex) {
746 			throw new IllegalArgumentException(String.format("Could not instantiate class [%s] specified " +
747 					"via 'contextInitializerClasses' init-param", className), ex);
748 		}
749 	}
750 
751 	/**
752 	 * Return the ServletContext attribute name for this servlet's WebApplicationContext.
753 	 * <p>The default implementation returns
754 	 * {@code SERVLET_CONTEXT_PREFIX + servlet name}.
755 	 * @see #SERVLET_CONTEXT_PREFIX
756 	 * @see #getServletName
757 	 */
758 	public String getServletContextAttributeName() {
759 		return SERVLET_CONTEXT_PREFIX + getServletName();
760 	}
761 
762 	/**
763 	 * Return this servlet's WebApplicationContext.
764 	 */
765 	public final WebApplicationContext getWebApplicationContext() {
766 		return this.webApplicationContext;
767 	}
768 
769 
770 	/**
771 	 * This method will be invoked after any bean properties have been set and
772 	 * the WebApplicationContext has been loaded. The default implementation is empty;
773 	 * subclasses may override this method to perform any initialization they require.
774 	 * @throws ServletException in case of an initialization exception
775 	 */
776 	protected void initFrameworkServlet() throws ServletException {
777 	}
778 
779 	/**
780 	 * Refresh this servlet's application context, as well as the
781 	 * dependent state of the servlet.
782 	 * @see #getWebApplicationContext()
783 	 * @see org.springframework.context.ConfigurableApplicationContext#refresh()
784 	 */
785 	public void refresh() {
786 		WebApplicationContext wac = getWebApplicationContext();
787 		if (!(wac instanceof ConfigurableApplicationContext)) {
788 			throw new IllegalStateException("WebApplicationContext does not support refresh: " + wac);
789 		}
790 		((ConfigurableApplicationContext) wac).refresh();
791 	}
792 
793 	/**
794 	 * Callback that receives refresh events from this servlet's WebApplicationContext.
795 	 * <p>The default implementation calls {@link #onRefresh},
796 	 * triggering a refresh of this servlet's context-dependent state.
797 	 * @param event the incoming ApplicationContext event
798 	 */
799 	public void onApplicationEvent(ContextRefreshedEvent event) {
800 		this.refreshEventReceived = true;
801 		onRefresh(event.getApplicationContext());
802 	}
803 
804 	/**
805 	 * Template method which can be overridden to add servlet-specific refresh work.
806 	 * Called after successful context refresh.
807 	 * <p>This implementation is empty.
808 	 * @param context the current WebApplicationContext
809 	 * @see #refresh()
810 	 */
811 	protected void onRefresh(ApplicationContext context) {
812 		// For subclasses: do nothing by default.
813 	}
814 
815 	/**
816 	 * Close the WebApplicationContext of this servlet.
817 	 * @see org.springframework.context.ConfigurableApplicationContext#close()
818 	 */
819 	@Override
820 	public void destroy() {
821 		getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
822 		// Only call close() on WebApplicationContext if locally managed...
823 		if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) {
824 			((ConfigurableApplicationContext) this.webApplicationContext).close();
825 		}
826 	}
827 
828 
829 	/**
830 	 * Override the parent class implementation in order to intercept PATCH
831 	 * requests.
832 	 */
833 	@Override
834 	protected void service(HttpServletRequest request, HttpServletResponse response)
835 			throws ServletException, IOException {
836 
837 		String method = request.getMethod();
838 		if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
839 			processRequest(request, response);
840 		}
841 		else {
842 			super.service(request, response);
843 		}
844 	}
845 
846 	/**
847 	 * Delegate GET requests to processRequest/doService.
848 	 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
849 	 * with a {@code NoBodyResponse} that just captures the content length.
850 	 * @see #doService
851 	 * @see #doHead
852 	 */
853 	@Override
854 	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
855 			throws ServletException, IOException {
856 
857 		processRequest(request, response);
858 	}
859 
860 	/**
861 	 * Delegate POST requests to {@link #processRequest}.
862 	 * @see #doService
863 	 */
864 	@Override
865 	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
866 			throws ServletException, IOException {
867 
868 		processRequest(request, response);
869 	}
870 
871 	/**
872 	 * Delegate PUT requests to {@link #processRequest}.
873 	 * @see #doService
874 	 */
875 	@Override
876 	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
877 			throws ServletException, IOException {
878 
879 		processRequest(request, response);
880 	}
881 
882 	/**
883 	 * Delegate DELETE requests to {@link #processRequest}.
884 	 * @see #doService
885 	 */
886 	@Override
887 	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
888 			throws ServletException, IOException {
889 
890 		processRequest(request, response);
891 	}
892 
893 	/**
894 	 * Delegate OPTIONS requests to {@link #processRequest}, if desired.
895 	 * <p>Applies HttpServlet's standard OPTIONS processing otherwise,
896 	 * and also if there is still no 'Allow' header set after dispatching.
897 	 * @see #doService
898 	 */
899 	@Override
900 	protected void doOptions(HttpServletRequest request, HttpServletResponse response)
901 			throws ServletException, IOException {
902 
903 		if (this.dispatchOptionsRequest) {
904 			processRequest(request, response);
905 			if (response.containsHeader("Allow")) {
906 				// Proper OPTIONS response coming from a handler - we're done.
907 				return;
908 			}
909 		}
910 
911 		// Use response wrapper for Servlet 2.5 compatibility where
912 		// the getHeader() method does not exist
913 		super.doOptions(request, new HttpServletResponseWrapper(response) {
914 			@Override
915 			public void setHeader(String name, String value) {
916 				if ("Allow".equals(name)) {
917 					value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name();
918 				}
919 				super.setHeader(name, value);
920 			}
921 		});
922 	}
923 
924 	/**
925 	 * Delegate TRACE requests to {@link #processRequest}, if desired.
926 	 * <p>Applies HttpServlet's standard TRACE processing otherwise.
927 	 * @see #doService
928 	 */
929 	@Override
930 	protected void doTrace(HttpServletRequest request, HttpServletResponse response)
931 			throws ServletException, IOException {
932 
933 		if (this.dispatchTraceRequest) {
934 			processRequest(request, response);
935 			if ("message/http".equals(response.getContentType())) {
936 				// Proper TRACE response coming from a handler - we're done.
937 				return;
938 			}
939 		}
940 		super.doTrace(request, response);
941 	}
942 
943 	/**
944 	 * Process this request, publishing an event regardless of the outcome.
945 	 * <p>The actual event handling is performed by the abstract
946 	 * {@link #doService} template method.
947 	 */
948 	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
949 			throws ServletException, IOException {
950 
951 		long startTime = System.currentTimeMillis();
952 		Throwable failureCause = null;
953 
954 		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
955 		LocaleContext localeContext = buildLocaleContext(request);
956 
957 		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
958 		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
959 
960 		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
961 		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
962 
963 		initContextHolders(request, localeContext, requestAttributes);
964 
965 		try {
966 			doService(request, response);
967 		}
968 		catch (ServletException ex) {
969 			failureCause = ex;
970 			throw ex;
971 		}
972 		catch (IOException ex) {
973 			failureCause = ex;
974 			throw ex;
975 		}
976 		catch (Throwable ex) {
977 			failureCause = ex;
978 			throw new NestedServletException("Request processing failed", ex);
979 		}
980 
981 		finally {
982 			resetContextHolders(request, previousLocaleContext, previousAttributes);
983 			if (requestAttributes != null) {
984 				requestAttributes.requestCompleted();
985 			}
986 
987 			if (logger.isDebugEnabled()) {
988 				if (failureCause != null) {
989 					this.logger.debug("Could not complete request", failureCause);
990 				}
991 				else {
992 					if (asyncManager.isConcurrentHandlingStarted()) {
993 						logger.debug("Leaving response open for concurrent processing");
994 					}
995 					else {
996 						this.logger.debug("Successfully completed request");
997 					}
998 				}
999 			}
1000 
1001 			publishRequestHandledEvent(request, response, startTime, failureCause);
1002 		}
1003 	}
1004 
1005 	/**
1006 	 * Build a LocaleContext for the given request, exposing the request's
1007 	 * primary locale as current locale.
1008 	 * @param request current HTTP request
1009 	 * @return the corresponding LocaleContext, or {@code null} if none to bind
1010 	 * @see LocaleContextHolder#setLocaleContext
1011 	 */
1012 	protected LocaleContext buildLocaleContext(HttpServletRequest request) {
1013 		return new SimpleLocaleContext(request.getLocale());
1014 	}
1015 
1016 	/**
1017 	 * Build ServletRequestAttributes for the given request (potentially also
1018 	 * holding a reference to the response), taking pre-bound attributes
1019 	 * (and their type) into consideration.
1020 	 * @param request current HTTP request
1021 	 * @param response current HTTP response
1022 	 * @param previousAttributes pre-bound RequestAttributes instance, if any
1023 	 * @return the ServletRequestAttributes to bind, or {@code null} to preserve
1024 	 * the previously bound instance (or not binding any, if none bound before)
1025 	 * @see RequestContextHolder#setRequestAttributes
1026 	 */
1027 	protected ServletRequestAttributes buildRequestAttributes(
1028 			HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {
1029 
1030 		if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
1031 			return new ServletRequestAttributes(request, response);
1032 		}
1033 		else {
1034 			return null;  // preserve the pre-bound RequestAttributes instance
1035 		}
1036 	}
1037 
1038 	private void initContextHolders(
1039 			HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
1040 
1041 		if (localeContext != null) {
1042 			LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
1043 		}
1044 		if (requestAttributes != null) {
1045 			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
1046 		}
1047 		if (logger.isTraceEnabled()) {
1048 			logger.trace("Bound request context to thread: " + request);
1049 		}
1050 	}
1051 
1052 	private void resetContextHolders(HttpServletRequest request,
1053 			LocaleContext prevLocaleContext, RequestAttributes previousAttributes) {
1054 
1055 		LocaleContextHolder.setLocaleContext(prevLocaleContext, this.threadContextInheritable);
1056 		RequestContextHolder.setRequestAttributes(previousAttributes, this.threadContextInheritable);
1057 		if (logger.isTraceEnabled()) {
1058 			logger.trace("Cleared thread-bound request context: " + request);
1059 		}
1060 	}
1061 
1062 	private void publishRequestHandledEvent(
1063 			HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
1064 
1065 		if (this.publishEvents) {
1066 			// Whether or not we succeeded, publish an event.
1067 			long processingTime = System.currentTimeMillis() - startTime;
1068 			int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
1069 			this.webApplicationContext.publishEvent(
1070 					new ServletRequestHandledEvent(this,
1071 							request.getRequestURI(), request.getRemoteAddr(),
1072 							request.getMethod(), getServletConfig().getServletName(),
1073 							WebUtils.getSessionId(request), getUsernameForRequest(request),
1074 							processingTime, failureCause, statusCode));
1075 		}
1076 	}
1077 
1078 	/**
1079 	 * Determine the username for the given request.
1080 	 * <p>The default implementation takes the name of the UserPrincipal, if any.
1081 	 * Can be overridden in subclasses.
1082 	 * @param request current HTTP request
1083 	 * @return the username, or {@code null} if none found
1084 	 * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
1085 	 */
1086 	protected String getUsernameForRequest(HttpServletRequest request) {
1087 		Principal userPrincipal = request.getUserPrincipal();
1088 		return (userPrincipal != null ? userPrincipal.getName() : null);
1089 	}
1090 
1091 
1092 	/**
1093 	 * Subclasses must implement this method to do the work of request handling,
1094 	 * receiving a centralized callback for GET, POST, PUT and DELETE.
1095 	 * <p>The contract is essentially the same as that for the commonly overridden
1096 	 * {@code doGet} or {@code doPost} methods of HttpServlet.
1097 	 * <p>This class intercepts calls to ensure that exception handling and
1098 	 * event publication takes place.
1099 	 * @param request current HTTP request
1100 	 * @param response current HTTP response
1101 	 * @throws Exception in case of any kind of processing failure
1102 	 * @see javax.servlet.http.HttpServlet#doGet
1103 	 * @see javax.servlet.http.HttpServlet#doPost
1104 	 */
1105 	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
1106 			throws Exception;
1107 
1108 
1109 	/**
1110 	 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
1111 	 * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
1112 	 */
1113 	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
1114 
1115 		@Override
1116 		public void onApplicationEvent(ContextRefreshedEvent event) {
1117 			FrameworkServlet.this.onApplicationEvent(event);
1118 		}
1119 	}
1120 
1121 
1122 	/**
1123 	 * CallableProcessingInterceptor implementation that initializes and resets
1124 	 * FrameworkServlet's context holders, i.e. LocaleContextHolder and RequestContextHolder.
1125 	 */
1126 	private class RequestBindingInterceptor extends CallableProcessingInterceptorAdapter {
1127 
1128 		@Override
1129 		public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {
1130 			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
1131 			if (request != null) {
1132 				HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);
1133 				initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));
1134 			}
1135 		}
1136 		@Override
1137 		public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {
1138 			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
1139 			if (request != null) {
1140 				resetContextHolders(request, null, null);
1141 			}
1142 		}
1143 	}
1144 
1145 }