更多精彩内容,欢迎观看:
浅析设计模式5 -- 责任链模式(上):https://developer.leiyu.cn/article/1263229?groupCode=taobaotech
Servlet 约定在请求进入容器后、执行 Servlet.service() 方法前,可以通过 Filter 对 web 资源进行过滤、权限鉴别等处理。在 tomcat 启动时,先加载所有的过滤器信息;在 tomcat 收到请求时,再加载并执行整个过滤器的链路,当请求从链路中脱离后,才会进入真正的业务接口,如下图所示。
在 tomcat 中,每一个 Filter 都是一个具体处理者,不仅能处理请求、还能处理响应。对于 request 来说,责任链结构为 Filter1 -> Filter2 -> Filter3;而对于响应来说,责任链结构为 Filter3 -> Filter2 -> Filter1。这种双向处理的思想其实也很经典,下面将简单分析一下源码。
public interface Filter { public default void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public default void destroy() {}}
Filter 为抽象处理者,提供了三个方法,其中 doFilter() 方法为处理方法,三个参数分别为请求、响应和链路管理器。接下来看一下链路管理器 FilterChain 的源码。
// FilterChainpublic interface FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;} // ApplicationFilterChainpublic final class ApplicationFilterChain implements FilterChain { // 处理器链路,ApplicationFilterConfig 可以理解为对 Filter 的包装 private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; // 当前处理器在链路中的索引 private int pos = 0; // 调用入口 @Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction() { @Override public Void run() throws ServletException, IOException { // here internalDoFilter(req,res); return null; } } ); } catch( PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; else if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new ServletException(e.getMessage(), e); } } else { // here internalDoFilter(request,response); } } // 开始处理 private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // 不停的驱动下一个过滤器 if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; try { Filter filter = filterConfig.getFilter(); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this}; SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal); } else { // 驱动过滤器 filter.doFilter(request, response, this); } } catch (IOException | ServletException | RuntimeException e) { throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); throw new ServletException(sm.getString("filterChain.filter"), e); } return; } // 链路中没有更多过滤器了,开始进入 servlet try { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(request); lastServicedResponse.set(response); } if (request.isAsyncSupported() && !servletSupportsAsync) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) && Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res}; SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal); } else { // 进入servlet 处理实际业务 servlet.service(request, response); } } catch (IOException | ServletException | RuntimeException e) { throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); throw new ServletException(sm.getString("filterChain.servlet"), e); } finally { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(null); lastServicedResponse.set(null); } } }}
ApplicationFilterChain 用数组来组织各处理者的先后顺序,并提供一个当前处理者在链路中的索引 pos 。当链路未在中途断开且当前处理者已是最后一个处理者时,调用 Servlet.service(request, response) 进入业务处理逻辑。作为用户,我们可以通过配置文件或者注入等方式,根据需要定义新的 Filter。
▐ 优点
▐ 缺点
▐ 适用场景
我们是大聚划算技术团队。负责支持聚划算、百亿补贴、天天特卖、淘特价等业务。我们聚焦优惠和选购体验,通过数智化驱动形成更有效率和确定性的货品运营方法论,为消费者提供精选和极致性价比的商品,为商家提供更具爆发确定性的营销方案。
Copyright © 2023 leiyu.cn. All Rights Reserved. 磊宇云计算 版权所有 许可证编号:B1-20233142/B2-20230630 山东磊宇云计算有限公司 鲁ICP备2020045424号
磊宇云计算致力于以最 “绿色节能” 的方式,让每一位上云的客户成为全球绿色节能和降低碳排放的贡献者