Java Servlet 3.0 Filter的asyncSupported何时设为false及相关疑问
问题整理
默认情况下Servlet Filter的asyncSupported属性值为false,对于设置请求/响应字符编码的简单过滤器来说,设为true似乎没什么问题,但如果保持默认值,异步Servlet会无法正常工作。以下是相关疑问的解答:
- 是否存在启用异步支持会造成危害的场景?
- 为何默认值不是
true、为何提供该配置选项? - 当
asyncSupported设为true时,过滤器是否需要调用HttpServletRequest.startAsync()? - 过滤器能否同时处理异步和同步运行模式?
- 在异步模式下,示例中的字符编码过滤器能否正确设置响应字符编码?
示例代码
@WebFilter(filterName = "CharacterEncodingFilter", urlPatterns = {"/*"}, dispatcherTypes = {DispatcherType.REQUEST}, asyncSupported = true) public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
问题解答
1. 是否存在启用异步支持会造成危害的场景?
有。如果过滤器或后续的Servlet/处理器依赖请求线程的上下文信息(比如ThreadLocal存储的用户会话、事务上下文),启用异步支持后,异步任务会在另一个线程执行,原线程的ThreadLocal数据无法被异步线程获取,会导致上下文丢失,引发逻辑错误。另外,若过滤器没有正确处理异步请求的生命周期(比如异步完成后未清理资源),可能造成资源泄漏。还有部分老旧第三方库未适配异步Servlet规范,在异步环境下可能抛出异常或行为异常。
2. 为何默认值不是true、为何提供该配置选项?
核心是兼容性考量。Servlet 3.0才引入异步支持,在此之前的Web应用全基于同步模型开发。如果默认把asyncSupported设为true,大量老旧应用的过滤器会因未适配异步模式出现问题(比如上述的ThreadLocal上下文丢失、资源未清理等)。提供这个配置选项,是为了让开发者按需启用异步支持,逐步迁移或适配异步场景,而非强制所有应用切换到异步模型。
3. 当asyncSupported设为true时,过滤器是否需要调用HttpServletRequest.startAsync()?
不需要。asyncSupported只是声明该过滤器支持异步请求的传递,允许后续Servlet调用startAsync()开启异步模式。启动异步的职责在具体业务Servlet或处理器那里,过滤器只需确保自身能处理异步请求的流转即可,无需主动调用该方法。
4. 过滤器能否同时处理异步和同步运行模式?
可以。只要asyncSupported设为true,过滤器就能兼容两种模式:
- 同步请求时,
doFilter方法在请求线程执行,流程和普通同步请求一致; - 后续Servlet开启异步后,
doFilter执行完成后请求线程会被释放,异步任务在其他线程执行,只要过滤器逻辑不依赖请求线程上下文,就无需额外修改即可适配。
5. 在异步模式下,示例中的字符编码过滤器能否正确设置响应字符编码?
可以。response.setCharacterEncoding("UTF-8")是将编码属性存储在HttpServletResponse对象中,后续不管是同步还是异步处理响应,输出时都会使用这个属性。异步模式下响应对象保持一致,后续异步任务输出响应时会沿用之前设置的编码,因此该过滤器的逻辑在异步场景下完全有效。
内容的提问来源于stack exchange,提问作者Ryan

