21
21
import java .util .ArrayList ;
22
22
import java .util .Collections ;
23
23
import java .util .concurrent .Callable ;
24
-
25
24
import javax .servlet .ServletContext ;
26
25
import javax .servlet .ServletException ;
27
26
import javax .servlet .http .HttpServletRequest ;
52
51
import org .springframework .web .context .request .RequestAttributes ;
53
52
import org .springframework .web .context .request .RequestContextHolder ;
54
53
import org .springframework .web .context .request .ServletRequestAttributes ;
55
- import org .springframework .web .context .request .async .CallableProcessingInterceptor ;
56
54
import org .springframework .web .context .request .async .CallableProcessingInterceptorAdapter ;
57
55
import org .springframework .web .context .request .async .WebAsyncManager ;
58
56
import org .springframework .web .context .request .async .WebAsyncUtils ;
@@ -785,6 +783,18 @@ protected void onRefresh(ApplicationContext context) {
785
783
// For subclasses: do nothing by default.
786
784
}
787
785
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
+
788
798
789
799
/**
790
800
* Override the parent class implementation in order to intercept PATCH
@@ -873,7 +883,7 @@ protected void doOptions(HttpServletRequest request, HttpServletResponse respons
873
883
super .doOptions (request , new HttpServletResponseWrapper (response ) {
874
884
@ Override
875
885
public void setHeader (String name , String value ) {
876
- if ("Allow" .equals (name )) {
886
+ if ("Allow" .equals (name )) {
877
887
value = (StringUtils .hasLength (value ) ? value + ", " : "" ) + RequestMethod .PATCH .name ();
878
888
}
879
889
super .setHeader (name , value );
@@ -915,15 +925,12 @@ protected final void processRequest(HttpServletRequest request, HttpServletRespo
915
925
LocaleContext localeContext = buildLocaleContext (request );
916
926
917
927
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 );
924
929
925
930
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 );
927
934
928
935
try {
929
936
doService (request , response );
@@ -950,46 +957,62 @@ protected final void processRequest(HttpServletRequest request, HttpServletRespo
950
957
if (logger .isDebugEnabled ()) {
951
958
if (failureCause != null ) {
952
959
this .logger .debug ("Could not complete request" , failureCause );
953
- } else {
960
+ }
961
+ else {
954
962
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" );
958
964
}
959
965
else {
960
966
this .logger .debug ("Successfully completed request" );
961
967
}
962
968
}
963
969
}
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 );
974
972
}
975
973
}
976
974
977
975
/**
978
976
* Build a LocaleContext for the given request, exposing the request's
979
977
* primary locale as current locale.
980
978
* @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
982
981
*/
983
982
protected LocaleContext buildLocaleContext (HttpServletRequest request ) {
984
983
return new SimpleLocaleContext (request .getLocale ());
985
984
}
986
985
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 ) {
989
1010
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 );
993
1016
}
994
1017
if (logger .isTraceEnabled ()) {
995
1018
logger .trace ("Bound request context to thread: " + request );
@@ -1006,17 +1029,17 @@ private void resetContextHolders(HttpServletRequest request,
1006
1029
}
1007
1030
}
1008
1031
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
+ }
1020
1043
}
1021
1044
1022
1045
/**
@@ -1032,6 +1055,7 @@ protected String getUsernameForRequest(HttpServletRequest request) {
1032
1055
return (userPrincipal != null ? userPrincipal .getName () : null );
1033
1056
}
1034
1057
1058
+
1035
1059
/**
1036
1060
* Subclasses must implement this method to do the work of request handling,
1037
1061
* receiving a centralized callback for GET, POST, PUT and DELETE.
@@ -1049,19 +1073,6 @@ protected abstract void doService(HttpServletRequest request, HttpServletRespons
1049
1073
throws Exception ;
1050
1074
1051
1075
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
-
1065
1076
/**
1066
1077
* ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
1067
1078
* only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
@@ -1073,4 +1084,28 @@ public void onApplicationEvent(ContextRefreshedEvent event) {
1073
1084
}
1074
1085
}
1075
1086
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
+
1076
1111
}
0 commit comments