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; 020import javax.servlet.FilterChain; 021import javax.servlet.ServletException; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import org.springframework.context.i18n.LocaleContextHolder; 026import org.springframework.web.context.request.RequestContextHolder; 027import org.springframework.web.context.request.ServletRequestAttributes; 028 029/** 030 * Servlet Filter that exposes the request to the current thread, 031 * through both {@link org.springframework.context.i18n.LocaleContextHolder} and 032 * {@link RequestContextHolder}. To be registered as filter in {@code web.xml}. 033 * 034 * <p>Alternatively, Spring's {@link org.springframework.web.context.request.RequestContextListener} 035 * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose 036 * the same request context to the current thread. 037 * 038 * <p>This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. 039 * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient. 040 * 041 * @author Juergen Hoeller 042 * @author Rod Johnson 043 * @author Rossen Stoyanchev 044 * @since 2.0 045 * @see org.springframework.context.i18n.LocaleContextHolder 046 * @see org.springframework.web.context.request.RequestContextHolder 047 * @see org.springframework.web.context.request.RequestContextListener 048 * @see org.springframework.web.servlet.DispatcherServlet 049 */ 050public class RequestContextFilter extends OncePerRequestFilter { 051 052 private boolean threadContextInheritable = false; 053 054 055 /** 056 * Set whether to expose the LocaleContext and RequestAttributes as inheritable 057 * for child threads (using an {@link java.lang.InheritableThreadLocal}). 058 * <p>Default is "false", to avoid side effects on spawned background threads. 059 * Switch this to "true" to enable inheritance for custom child threads which 060 * are spawned during request processing and only used for this request 061 * (that is, ending after their initial task, without reuse of the thread). 062 * <p><b>WARNING:</b> Do not use inheritance for child threads if you are 063 * accessing a thread pool which is configured to potentially add new threads 064 * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}), 065 * since this will expose the inherited context to such a pooled thread. 066 */ 067 public void setThreadContextInheritable(boolean threadContextInheritable) { 068 this.threadContextInheritable = threadContextInheritable; 069 } 070 071 072 /** 073 * Returns "false" so that the filter may set up the request context in each 074 * asynchronously dispatched thread. 075 */ 076 @Override 077 protected boolean shouldNotFilterAsyncDispatch() { 078 return false; 079 } 080 081 /** 082 * Returns "false" so that the filter may set up the request context in an 083 * error dispatch. 084 */ 085 @Override 086 protected boolean shouldNotFilterErrorDispatch() { 087 return false; 088 } 089 090 @Override 091 protected void doFilterInternal( 092 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 093 throws ServletException, IOException { 094 095 ServletRequestAttributes attributes = new ServletRequestAttributes(request, response); 096 initContextHolders(request, attributes); 097 098 try { 099 filterChain.doFilter(request, response); 100 } 101 finally { 102 resetContextHolders(); 103 if (logger.isDebugEnabled()) { 104 logger.debug("Cleared thread-bound request context: " + request); 105 } 106 attributes.requestCompleted(); 107 } 108 } 109 110 private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) { 111 LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable); 112 RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); 113 if (logger.isDebugEnabled()) { 114 logger.debug("Bound request context to thread: " + request); 115 } 116 } 117 118 private void resetContextHolders() { 119 LocaleContextHolder.resetLocaleContext(); 120 RequestContextHolder.resetRequestAttributes(); 121 } 122 123}