提交 1f55b4f2 编写于 作者: J Juergen Hoeller

Extracted buildRequestAttributes template method from FrameworkServlet

Also, RequestBindingInterceptor now obtains HttpServletRequest from locally passed-in request handle and delegates to buildRequestAttributes as well now.

Issue: SPR-10342
上级 43c1cec7
...@@ -21,7 +21,6 @@ import java.security.Principal; ...@@ -21,7 +21,6 @@ import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -52,7 +51,6 @@ import org.springframework.web.context.request.NativeWebRequest; ...@@ -52,7 +51,6 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter; import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager; import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils; import org.springframework.web.context.request.async.WebAsyncUtils;
...@@ -785,6 +783,18 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -785,6 +783,18 @@ public abstract class FrameworkServlet extends HttpServletBean {
// For subclasses: do nothing by default. // For subclasses: do nothing by default.
} }
/**
* Close the WebApplicationContext of this servlet.
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
@Override
public void destroy() {
getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) this.webApplicationContext).close();
}
}
/** /**
* Override the parent class implementation in order to intercept PATCH * Override the parent class implementation in order to intercept PATCH
...@@ -873,7 +883,7 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -873,7 +883,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
super.doOptions(request, new HttpServletResponseWrapper(response) { super.doOptions(request, new HttpServletResponseWrapper(response) {
@Override @Override
public void setHeader(String name, String value) { public void setHeader(String name, String value) {
if("Allow".equals(name)) { if ("Allow".equals(name)) {
value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name(); value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name();
} }
super.setHeader(name, value); super.setHeader(name, value);
...@@ -915,15 +925,12 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -915,15 +925,12 @@ public abstract class FrameworkServlet extends HttpServletBean {
LocaleContext localeContext = buildLocaleContext(request); LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = null; ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
if (previousAttributes == null || (previousAttributes instanceof ServletRequestAttributes)) {
requestAttributes = new ServletRequestAttributes(request);
}
initContextHolders(request, localeContext, requestAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), getRequestBindingInterceptor(request)); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try { try {
doService(request, response); doService(request, response);
...@@ -950,27 +957,18 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -950,27 +957,18 @@ public abstract class FrameworkServlet extends HttpServletBean {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
if (failureCause != null) { if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause); this.logger.debug("Could not complete request", failureCause);
} else { }
else {
if (asyncManager.isConcurrentHandlingStarted()) { if (asyncManager.isConcurrentHandlingStarted()) {
if (logger.isDebugEnabled()) { logger.debug("Leaving response open for concurrent processing");
logger.debug("Leaving response open for concurrent processing");
}
} }
else { else {
this.logger.debug("Successfully completed request"); this.logger.debug("Successfully completed request");
} }
} }
} }
if (this.publishEvents) {
// Whether or not we succeeded, publish an event. publishRequestHandledEvent(request, startTime, failureCause);
long processingTime = System.currentTimeMillis() - startTime;
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause));
}
} }
} }
...@@ -978,18 +976,43 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -978,18 +976,43 @@ public abstract class FrameworkServlet extends HttpServletBean {
* Build a LocaleContext for the given request, exposing the request's * Build a LocaleContext for the given request, exposing the request's
* primary locale as current locale. * primary locale as current locale.
* @param request current HTTP request * @param request current HTTP request
* @return the corresponding LocaleContext * @return the corresponding LocaleContext, or {@code null} if none to bind
* @see LocaleContextHolder#setLocaleContext
*/ */
protected LocaleContext buildLocaleContext(HttpServletRequest request) { protected LocaleContext buildLocaleContext(HttpServletRequest request) {
return new SimpleLocaleContext(request.getLocale()); return new SimpleLocaleContext(request.getLocale());
} }
private void initContextHolders(HttpServletRequest request, /**
LocaleContext localeContext, RequestAttributes attributes) { * Build ServletRequestAttributes for the given request (potentially also
* holding a reference to the response), taking pre-bound attributes
* (and their type) into consideration.
* @param request current HTTP request
* @param response current HTTP response
* @param previousAttributes pre-bound RequestAttributes instance, if any
* @return the ServletRequestAttributes to bind, or {@code null} to preserve
* the previously bound instance (or not binding any, if none bound before)
* @see RequestContextHolder#setRequestAttributes
*/
protected ServletRequestAttributes buildRequestAttributes(
HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {
if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
return new ServletRequestAttributes(request);
}
else {
return null; // preserve the pre-bound RequestAttributes instance
}
}
private void initContextHolders(
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable); if (localeContext != null) {
if (attributes != null) { LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
RequestContextHolder.setRequestAttributes(attributes, this.threadContextInheritable); }
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
} }
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Bound request context to thread: " + request); logger.trace("Bound request context to thread: " + request);
...@@ -1006,17 +1029,17 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -1006,17 +1029,17 @@ public abstract class FrameworkServlet extends HttpServletBean {
} }
} }
private CallableProcessingInterceptor getRequestBindingInterceptor(final HttpServletRequest request) { private void publishRequestHandledEvent(HttpServletRequest request, long startTime, Throwable failureCause) {
return new CallableProcessingInterceptorAdapter() { if (this.publishEvents) {
@Override // Whether or not we succeeded, publish an event.
public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) { long processingTime = System.currentTimeMillis() - startTime;
initContextHolders(request, buildLocaleContext(request), new ServletRequestAttributes(request)); this.webApplicationContext.publishEvent(
} new ServletRequestHandledEvent(this,
@Override request.getRequestURI(), request.getRemoteAddr(),
public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) { request.getMethod(), getServletConfig().getServletName(),
resetContextHolders(request, null, null); WebUtils.getSessionId(request), getUsernameForRequest(request),
} processingTime, failureCause));
}; }
} }
/** /**
...@@ -1032,6 +1055,7 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -1032,6 +1055,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
return (userPrincipal != null ? userPrincipal.getName() : null); return (userPrincipal != null ? userPrincipal.getName() : null);
} }
/** /**
* Subclasses must implement this method to do the work of request handling, * Subclasses must implement this method to do the work of request handling,
* receiving a centralized callback for GET, POST, PUT and DELETE. * receiving a centralized callback for GET, POST, PUT and DELETE.
...@@ -1049,19 +1073,6 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -1049,19 +1073,6 @@ public abstract class FrameworkServlet extends HttpServletBean {
throws Exception; throws Exception;
/**
* Close the WebApplicationContext of this servlet.
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
@Override
public void destroy() {
getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) this.webApplicationContext).close();
}
}
/** /**
* ApplicationListener endpoint that receives events from this servlet's WebApplicationContext * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
* only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance. * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
...@@ -1073,4 +1084,28 @@ public abstract class FrameworkServlet extends HttpServletBean { ...@@ -1073,4 +1084,28 @@ public abstract class FrameworkServlet extends HttpServletBean {
} }
} }
/**
* CallableProcessingInterceptor implementation that initializes and resets
* FrameworkServlet's context holders, i.e. LocaleContextHolder and RequestContextHolder.
*/
private class RequestBindingInterceptor extends CallableProcessingInterceptorAdapter {
@Override
public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);
initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));
}
}
@Override
public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
resetContextHolders(request, null, null);
}
}
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册