电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Tomcat中Filter的執行流程

瀏覽:201日期:2023-09-08 20:45:27
目錄前言1、Filter接口2、FilterChain接口執行流程1、創建filterChain2、執行dofilter前言

Filter是什么?Filter是servlet規范中定義的java web組件, 在所有支持java web的容器中都可以使用 它是位于前端請求到servlet之間的一系列過濾器,也可以稱之為中間件,它主要是對請求到達servlet之前做一些額外的動作:

1、權限控制2、監控3、日志管理4、等等

這里涉及到兩個接口:Filter和FilterChain

Filter和FilterChain密不可分, Filter可以實現依次調用正是因為有了FilterChain。

1、Filter接口public interface Filter { // 容器創建的時候調用, 即啟動tomcat的時候調用 public void init(FilterConfig filterConfig) throws ServletException; // 由FilterChain調用, 并且傳入FilterChain本身, 最后回調FilterChain的doFilter()方法 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; // 容器銷毀的時候調用, 即關閉tomcat的時候調用 public void destroy(); }2、FilterChain接口public interface FilterChain { // 由Filter.doFilter()中的chain.doFilter調用 public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;}執行流程

在前面的文章中,我們知道,tomcat啟動會執行StandardWrapperValve.java類的invoke方法:

public final void invoke(Request request, Response response){ ...... MessageBytes requestPathMB = request.getRequestPathMB(); DispatcherType dispatcherType = DispatcherType.REQUEST; if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); // Create the filter chain for this request ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); // Call the filter chain for this request // NOTE: This also calls the servlet's service() method Container container = this.container; try { if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) {try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch(); } else { filterChain.doFilter(request.getRequest(),response.getResponse()); }} finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); }} } else {if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch();} else { filterChain.doFilter (request.getRequest(), response.getResponse());} } } } catch (ClientAbortException | CloseNowException e) { } ......}

上面的代碼做了如下一些動作:

1、每次請求過來都會創建一個過濾器鏈(filterChain),并把待執行的servlet對象存放到過濾器鏈中。對于每個url,對應的filter個數都是不固定的,filterchain需要保存每個請求所對應的一個filter數組,以及調用到的filter的position,以便繼續向下調用filter。2、創建了filterChain之后,就開始執行doFilter進行請求的鏈式處理。1、創建filterChain

下面我們具體來看看filterChain是怎么創建的

public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) { // If there is no servlet to execute, return null if (servlet == null) return null; // Create and initialize a filter chain object ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; if (Globals.IS_SECURITY_ENABLED) { // Security: Do not recycle filterChain = new ApplicationFilterChain(); } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) {filterChain = new ApplicationFilterChain();req.setFilterChain(filterChain); } } } else { // Request dispatcher in use filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // Acquire the filter mappings for this Context StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return filterChain; // Acquire the information we will need to match filter mappings DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null; Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null){ requestPath = attribute.toString(); } String servletName = wrapper.getName(); // Add the relevant path-mapped filters to this filter chain for (FilterMap filterMap : filterMaps) { if (!matchDispatcher(filterMap, dispatcher)) { continue; } if (!matchFiltersURL(filterMap, requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // Add filters that match on servlet name second for (FilterMap filterMap : filterMaps) { if (!matchDispatcher(filterMap, dispatcher)) { continue; } if (!matchFiltersServlet(filterMap, servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // Return the completed filter chain return filterChain;}

上面的代碼做了一下幾件事:

1、把要執行的servlet存放到過濾器鏈中。2、如果沒有配置過濾器則return一個空的過濾器鏈(只包含上面設置的servlet)。3、如果配置url-pattern過濾器,則把匹配的過濾器加入到過濾器鏈中4、如果配置servlet-name過濾器,則把匹配的過濾器加入到過濾器鏈中

注意: filterChain.addFilter()順序與web.xml中定義的Filter順序一致,所以過濾器的執行順序是按定義的上下順序決定的。

2、執行dofilter

創建了chain之后,就開始執行鏈式請求了,具體的邏輯如下:

private void internalDoFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException { // Call the next filter if there is one 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; } // We fell off the end of the chain -- call the servlet instance try { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(request); lastServicedResponse.set(response); } if (request.isAsyncSupported() && !servletSupportsAsync) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } // Use potentially wrapped request from this point 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.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); } }}

上面的代碼邏輯如下:

1、通過position索引判斷是否執行完了所有的filter2、如果沒有,取出當前待執行的索引filter,調用其doFilter方法,在上面的接口說明中,我們看到,所有的filter類都繼承了filter接口,都實現了dofilter方法;我們也注意到,該方法接收一個filterChain對象。在這段代碼中,filter.doFilter(request, response, this);可以看到,將自身引用傳遞進去了,那么各個filter在dofilter的方法中,可以根據自身業務需要,來判斷是否需要繼續進行下面的filter鏈式執行,如果需要,就執行filterChain.doFilter方法,此時就又回到了此代碼中。如果反復3、如果執行完了所有的filter,則開始執行servlet業務模塊servlet.service(request, response);

以上就是詳解Tomcat中Filter是怎樣執行的的詳細內容,更多關于Tomcat Filter執行的資料請關注好吧啦網其它相關文章!

標簽: Tomcat
主站蜘蛛池模板: 航空障碍灯_高中低光强航空障碍灯_民航许可认证航空警示灯厂家-东莞市天翔航天科技有限公司 | 探鸣起名网-品牌起名-英文商标起名-公司命名-企业取名包满意 | 台湾阳明固态继电器-奥托尼克斯光电传感器-接近开关-温控器-光纤传感器-编码器一级代理商江苏用之宜电气 | 污水提升器,污水提升泵,地下室排水,增压泵,雨水泵,智能供排水控制器-上海智流泵业有限公司 | 冷却塔降噪隔音_冷却塔噪声治理_冷却塔噪音处理厂家-广东康明冷却塔降噪厂家 | 悬浮拼装地板_篮球场木地板翻新_运动木地板价格-上海越禾运动地板厂家 | 烟气在线监测系统_烟气在线监测仪_扬尘检测仪_空气质量监测站「山东风途物联网」 | 2025黄道吉日查询、吉时查询、老黄历查询平台- 黄道吉日查询网 | 自动气象站_气象站监测设备_全自动气象站设备_雨量监测站-山东风途物联网 | 杭州月嫂技术培训服务公司-催乳师培训中心报名费用-产后康复师培训机构-杭州优贝姆健康管理有限公司 | 圆盘鞋底注塑机_连帮鞋底成型注塑机-温州天钢机械有限公司 | 无菌实验室规划装修设计-一体化实验室承包-北京洁净净化工程建设施工-北京航天科恩实验室装备工程技术有限公司 | 游戏版号转让_游戏资质出售_游戏公司转让-【八九买卖网】 | 药品/药物稳定性试验考察箱-埃里森仪器设备(上海)有限公司 | 垃圾处理设备_餐厨垃圾处理设备_厨余垃圾处理设备_果蔬垃圾处理设备-深圳市三盛环保科技有限公司 | 河南不锈钢水箱_地埋水箱_镀锌板水箱_消防水箱厂家-河南联固供水设备有限公司 | 工业设计,人工智能,体验式3D展示的智能技术交流服务平台-纳金网 J.S.Bach 圣巴赫_高端背景音乐系统_官网 | 企业彩铃制作_移动、联通、电信集团彩铃上传开通_彩铃定制_商务彩铃管理平台-集团彩铃网 | 冰晶石|碱性嫩黄闪蒸干燥机-有机垃圾烘干设备-草酸钙盘式干燥机-常州市宝康干燥 | 江苏皓越真空设备有限公司| 不锈钢轴流风机,不锈钢电机-许昌光维防爆电机有限公司(原许昌光维特种电机技术有限公司) | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 集装袋吨袋生产厂家-噸袋廠傢-塑料编织袋-纸塑复合袋-二手吨袋-太空袋-曹县建烨包装 | 餐饮小吃技术培训-火锅串串香培训「何小胖培训」_成都点石成金[官网] | 细石混凝土泵_厂家_价格-烟台九达机械有限公司 | 万濠投影仪_瑞士TRIMOS高度仪_尼康投影仪V12BDC|量子仪器 | 长沙一级消防工程公司_智能化弱电_机电安装_亮化工程专业施工承包_湖南公共安全工程有限公司 | 衬塑管道_衬四氟管道厂家-淄博恒固化工设备有限公司 | 不锈钢监控杆_监控立杆厂家-廊坊耀星光电科技有限公司 | 南京交通事故律师-专打交通事故的南京律师 | 浙江红酒库-冰雕库-气调库-茶叶库安装-医药疫苗冷库-食品物流恒温恒湿车间-杭州领顺实业有限公司 | 深圳装修_店面装修设计_餐厅设计_装修全包价格-尚泰装饰设计 | 高效节能电机_伺服主轴电机_铜转子电机_交流感应伺服电机_图片_型号_江苏智马科技有限公司 | 细砂提取机,隔膜板框泥浆污泥压滤机,螺旋洗砂机设备,轮式洗砂机械,机制砂,圆锥颚式反击式破碎机,振动筛,滚筒筛,喂料机- 上海重睿环保设备有限公司 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 层流手术室净化装修-检验科ICU改造施工-华锐净化工程-特殊科室建设厂家 | 威实软件_软件定制开发_OA_OA办公系统_OA系统_办公自动化软件 | J.S.Bach 圣巴赫_高端背景音乐系统_官网| 钢骨架轻型板_膨石轻型板_钢骨架轻型板价格_恒道新材料 | 半自动预灌装机,卡式瓶灌装机,注射器灌装机,给药器灌装机,大输液灌装机,西林瓶灌装机-长沙一星制药机械有限公司 | 游泳池设备安装工程_恒温泳池设备_儿童游泳池设备厂家_游泳池水处理设备-东莞市君达泳池设备有限公司 |