001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.filter; 018 019import java.io.IOException; 020 021import javax.servlet.FilterChain; 022import javax.servlet.ServletException; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025 026import org.springframework.context.i18n.LocaleContextHolder; 027import org.springframework.web.context.request.RequestContextHolder; 028import org.springframework.web.context.request.ServletRequestAttributes; 029 030/** 031 * Servlet Filter that exposes the request to the current thread, 032 * through both {@link org.springframework.context.i18n.LocaleContextHolder} and 033 * {@link RequestContextHolder}. To be registered as filter in {@code web.xml}. 034 * 035 * <p>Alternatively, Spring's {@link org.springframework.web.context.request.RequestContextListener} 036 * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose 037 * the same request context to the current thread. 038 * 039 * <p>This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. 040 * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient. 041 * 042 * @author Juergen Hoeller 043 * @author Rod Johnson 044 * @author Rossen Stoyanchev 045 * @since 2.0 046 * @see org.springframework.context.i18n.LocaleContextHolder 047 * @see org.springframework.web.context.request.RequestContextHolder 048 * @see org.springframework.web.context.request.RequestContextListener 049 * @see org.springframework.web.servlet.DispatcherServlet 050 */ 051public class RequestContextFilter extends OncePerRequestFilter { 052 053 private boolean threadContextInheritable = false; 054 055 056 /** 057 * Set whether to expose the LocaleContext and RequestAttributes as inheritable 058 * for child threads (using an {@link java.lang.InheritableThreadLocal}). 059 * <p>Default is "false", to avoid side effects on spawned background threads. 060 * Switch this to "true" to enable inheritance for custom child threads which 061 * are spawned during request processing and only used for this request 062 * (that is, ending after their initial task, without reuse of the thread). 063 * <p><b>WARNING:</b> Do not use inheritance for child threads if you are 064 * accessing a thread pool which is configured to potentially add new threads 065 * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}), 066 * since this will expose the inherited context to such a pooled thread. 067 */ 068 public void setThreadContextInheritable(boolean threadContextInheritable) { 069 this.threadContextInheritable = threadContextInheritable; 070 } 071 072 073 /** 074 * Returns "false" so that the filter may set up the request context in each 075 * asynchronously dispatched thread. 076 */ 077 @Override 078 protected boolean shouldNotFilterAsyncDispatch() { 079 return false; 080 } 081 082 /** 083 * Returns "false" so that the filter may set up the request context in an 084 * error dispatch. 085 */ 086 @Override 087 protected boolean shouldNotFilterErrorDispatch() { 088 return false; 089 } 090 091 @Override 092 protected void doFilterInternal( 093 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 094 throws ServletException, IOException { 095 096 ServletRequestAttributes attributes = new ServletRequestAttributes(request, response); 097 initContextHolders(request, attributes); 098 099 try { 100 filterChain.doFilter(request, response); 101 } 102 finally { 103 resetContextHolders(); 104 if (logger.isTraceEnabled()) { 105 logger.trace("Cleared thread-bound request context: " + request); 106 } 107 attributes.requestCompleted(); 108 } 109 } 110 111 private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) { 112 LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable); 113 RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); 114 if (logger.isTraceEnabled()) { 115 logger.trace("Bound request context to thread: " + request); 116 } 117 } 118 119 private void resetContextHolders() { 120 LocaleContextHolder.resetLocaleContext(); 121 RequestContextHolder.resetRequestAttributes(); 122 } 123 124}