Skip to content

Commit 1f55b4f

Browse files
committed
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
1 parent 43c1cec commit 1f55b4f

File tree

1 file changed

+89
-54
lines changed

1 file changed

+89
-54
lines changed

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

Lines changed: 89 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.ArrayList;
2222
import java.util.Collections;
2323
import java.util.concurrent.Callable;
24-
2524
import javax.servlet.ServletContext;
2625
import javax.servlet.ServletException;
2726
import javax.servlet.http.HttpServletRequest;
@@ -52,7 +51,6 @@
5251
import org.springframework.web.context.request.RequestAttributes;
5352
import org.springframework.web.context.request.RequestContextHolder;
5453
import org.springframework.web.context.request.ServletRequestAttributes;
55-
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
5654
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
5755
import org.springframework.web.context.request.async.WebAsyncManager;
5856
import org.springframework.web.context.request.async.WebAsyncUtils;
@@ -785,6 +783,18 @@ protected void onRefresh(ApplicationContext context) {
785783
// For subclasses: do nothing by default.
786784
}
787785

786+
/**
787+
* Close the WebApplicationContext of this servlet.
788+
* @see org.springframework.context.ConfigurableApplicationContext#close()
789+
*/
790+
@Override
791+
public void destroy() {
792+
getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
793+
if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
794+
((ConfigurableApplicationContext) this.webApplicationContext).close();
795+
}
796+
}
797+
788798

789799
/**
790800
* Override the parent class implementation in order to intercept PATCH
@@ -873,7 +883,7 @@ protected void doOptions(HttpServletRequest request, HttpServletResponse respons
873883
super.doOptions(request, new HttpServletResponseWrapper(response) {
874884
@Override
875885
public void setHeader(String name, String value) {
876-
if("Allow".equals(name)) {
886+
if ("Allow".equals(name)) {
877887
value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name();
878888
}
879889
super.setHeader(name, value);
@@ -915,15 +925,12 @@ protected final void processRequest(HttpServletRequest request, HttpServletRespo
915925
LocaleContext localeContext = buildLocaleContext(request);
916926

917927
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
918-
ServletRequestAttributes requestAttributes = null;
919-
if (previousAttributes == null || (previousAttributes instanceof ServletRequestAttributes)) {
920-
requestAttributes = new ServletRequestAttributes(request);
921-
}
922-
923-
initContextHolders(request, localeContext, requestAttributes);
928+
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
924929

925930
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
926-
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), getRequestBindingInterceptor(request));
931+
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
932+
933+
initContextHolders(request, localeContext, requestAttributes);
927934

928935
try {
929936
doService(request, response);
@@ -950,46 +957,62 @@ protected final void processRequest(HttpServletRequest request, HttpServletRespo
950957
if (logger.isDebugEnabled()) {
951958
if (failureCause != null) {
952959
this.logger.debug("Could not complete request", failureCause);
953-
} else {
960+
}
961+
else {
954962
if (asyncManager.isConcurrentHandlingStarted()) {
955-
if (logger.isDebugEnabled()) {
956-
logger.debug("Leaving response open for concurrent processing");
957-
}
963+
logger.debug("Leaving response open for concurrent processing");
958964
}
959965
else {
960966
this.logger.debug("Successfully completed request");
961967
}
962968
}
963969
}
964-
if (this.publishEvents) {
965-
// Whether or not we succeeded, publish an event.
966-
long processingTime = System.currentTimeMillis() - startTime;
967-
this.webApplicationContext.publishEvent(
968-
new ServletRequestHandledEvent(this,
969-
request.getRequestURI(), request.getRemoteAddr(),
970-
request.getMethod(), getServletConfig().getServletName(),
971-
WebUtils.getSessionId(request), getUsernameForRequest(request),
972-
processingTime, failureCause));
973-
}
970+
971+
publishRequestHandledEvent(request, startTime, failureCause);
974972
}
975973
}
976974

977975
/**
978976
* Build a LocaleContext for the given request, exposing the request's
979977
* primary locale as current locale.
980978
* @param request current HTTP request
981-
* @return the corresponding LocaleContext
979+
* @return the corresponding LocaleContext, or {@code null} if none to bind
980+
* @see LocaleContextHolder#setLocaleContext
982981
*/
983982
protected LocaleContext buildLocaleContext(HttpServletRequest request) {
984983
return new SimpleLocaleContext(request.getLocale());
985984
}
986985

987-
private void initContextHolders(HttpServletRequest request,
988-
LocaleContext localeContext, RequestAttributes attributes) {
986+
/**
987+
* Build ServletRequestAttributes for the given request (potentially also
988+
* holding a reference to the response), taking pre-bound attributes
989+
* (and their type) into consideration.
990+
* @param request current HTTP request
991+
* @param response current HTTP response
992+
* @param previousAttributes pre-bound RequestAttributes instance, if any
993+
* @return the ServletRequestAttributes to bind, or {@code null} to preserve
994+
* the previously bound instance (or not binding any, if none bound before)
995+
* @see RequestContextHolder#setRequestAttributes
996+
*/
997+
protected ServletRequestAttributes buildRequestAttributes(
998+
HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {
999+
1000+
if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
1001+
return new ServletRequestAttributes(request);
1002+
}
1003+
else {
1004+
return null; // preserve the pre-bound RequestAttributes instance
1005+
}
1006+
}
1007+
1008+
private void initContextHolders(
1009+
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
9891010

990-
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
991-
if (attributes != null) {
992-
RequestContextHolder.setRequestAttributes(attributes, this.threadContextInheritable);
1011+
if (localeContext != null) {
1012+
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
1013+
}
1014+
if (requestAttributes != null) {
1015+
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
9931016
}
9941017
if (logger.isTraceEnabled()) {
9951018
logger.trace("Bound request context to thread: " + request);
@@ -1006,17 +1029,17 @@ private void resetContextHolders(HttpServletRequest request,
10061029
}
10071030
}
10081031

1009-
private CallableProcessingInterceptor getRequestBindingInterceptor(final HttpServletRequest request) {
1010-
return new CallableProcessingInterceptorAdapter() {
1011-
@Override
1012-
public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {
1013-
initContextHolders(request, buildLocaleContext(request), new ServletRequestAttributes(request));
1014-
}
1015-
@Override
1016-
public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {
1017-
resetContextHolders(request, null, null);
1018-
}
1019-
};
1032+
private void publishRequestHandledEvent(HttpServletRequest request, long startTime, Throwable failureCause) {
1033+
if (this.publishEvents) {
1034+
// Whether or not we succeeded, publish an event.
1035+
long processingTime = System.currentTimeMillis() - startTime;
1036+
this.webApplicationContext.publishEvent(
1037+
new ServletRequestHandledEvent(this,
1038+
request.getRequestURI(), request.getRemoteAddr(),
1039+
request.getMethod(), getServletConfig().getServletName(),
1040+
WebUtils.getSessionId(request), getUsernameForRequest(request),
1041+
processingTime, failureCause));
1042+
}
10201043
}
10211044

10221045
/**
@@ -1032,6 +1055,7 @@ protected String getUsernameForRequest(HttpServletRequest request) {
10321055
return (userPrincipal != null ? userPrincipal.getName() : null);
10331056
}
10341057

1058+
10351059
/**
10361060
* Subclasses must implement this method to do the work of request handling,
10371061
* receiving a centralized callback for GET, POST, PUT and DELETE.
@@ -1049,19 +1073,6 @@ protected abstract void doService(HttpServletRequest request, HttpServletRespons
10491073
throws Exception;
10501074

10511075

1052-
/**
1053-
* Close the WebApplicationContext of this servlet.
1054-
* @see org.springframework.context.ConfigurableApplicationContext#close()
1055-
*/
1056-
@Override
1057-
public void destroy() {
1058-
getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
1059-
if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
1060-
((ConfigurableApplicationContext) this.webApplicationContext).close();
1061-
}
1062-
}
1063-
1064-
10651076
/**
10661077
* ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
10671078
* only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
@@ -1073,4 +1084,28 @@ public void onApplicationEvent(ContextRefreshedEvent event) {
10731084
}
10741085
}
10751086

1087+
1088+
/**
1089+
* CallableProcessingInterceptor implementation that initializes and resets
1090+
* FrameworkServlet's context holders, i.e. LocaleContextHolder and RequestContextHolder.
1091+
*/
1092+
private class RequestBindingInterceptor extends CallableProcessingInterceptorAdapter {
1093+
1094+
@Override
1095+
public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {
1096+
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
1097+
if (request != null) {
1098+
HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);
1099+
initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));
1100+
}
1101+
}
1102+
@Override
1103+
public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {
1104+
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
1105+
if (request != null) {
1106+
resetContextHolders(request, null, null);
1107+
}
1108+
}
1109+
}
1110+
10761111
}

0 commit comments

Comments
 (0)