亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解Tomcat中Filter的執(zhí)行流程

瀏覽:137日期:2023-09-08 20:45:27
目錄前言1、Filter接口2、FilterChain接口執(zhí)行流程1、創(chuàng)建filterChain2、執(zhí)行dofilter前言

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

1、權(quán)限控制2、監(jiān)控3、日志管理4、等等

這里涉及到兩個(gè)接口:Filter和FilterChain

Filter和FilterChain密不可分, Filter可以實(shí)現(xiàn)依次調(diào)用正是因?yàn)橛辛薋ilterChain。

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

在前面的文章中,我們知道,tomcat啟動(dòng)會(huì)執(zhí)行StandardWrapperValve.java類(lèi)的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) { } ......}

上面的代碼做了如下一些動(dòng)作:

1、每次請(qǐng)求過(guò)來(lái)都會(huì)創(chuàng)建一個(gè)過(guò)濾器鏈(filterChain),并把待執(zhí)行的servlet對(duì)象存放到過(guò)濾器鏈中。對(duì)于每個(gè)url,對(duì)應(yīng)的filter個(gè)數(shù)都是不固定的,filterchain需要保存每個(gè)請(qǐng)求所對(duì)應(yīng)的一個(gè)filter數(shù)組,以及調(diào)用到的filter的position,以便繼續(xù)向下調(diào)用filter。2、創(chuàng)建了filterChain之后,就開(kāi)始執(zhí)行doFilter進(jìn)行請(qǐng)求的鏈?zhǔn)教幚怼?、創(chuàng)建filterChain

下面我們具體來(lái)看看filterChain是怎么創(chuàng)建的

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、把要執(zhí)行的servlet存放到過(guò)濾器鏈中。2、如果沒(méi)有配置過(guò)濾器則return一個(gè)空的過(guò)濾器鏈(只包含上面設(shè)置的servlet)。3、如果配置url-pattern過(guò)濾器,則把匹配的過(guò)濾器加入到過(guò)濾器鏈中4、如果配置servlet-name過(guò)濾器,則把匹配的過(guò)濾器加入到過(guò)濾器鏈中

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

2、執(zhí)行dofilter

創(chuàng)建了chain之后,就開(kāi)始執(zhí)行鏈?zhǔn)秸?qǐng)求了,具體的邏輯如下:

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、通過(guò)position索引判斷是否執(zhí)行完了所有的filter2、如果沒(méi)有,取出當(dāng)前待執(zhí)行的索引filter,調(diào)用其doFilter方法,在上面的接口說(shuō)明中,我們看到,所有的filter類(lèi)都繼承了filter接口,都實(shí)現(xiàn)了dofilter方法;我們也注意到,該方法接收一個(gè)filterChain對(duì)象。在這段代碼中,filter.doFilter(request, response, this);可以看到,將自身引用傳遞進(jìn)去了,那么各個(gè)filter在dofilter的方法中,可以根據(jù)自身業(yè)務(wù)需要,來(lái)判斷是否需要繼續(xù)進(jìn)行下面的filter鏈?zhǔn)綀?zhí)行,如果需要,就執(zhí)行filterChain.doFilter方法,此時(shí)就又回到了此代碼中。如果反復(fù)3、如果執(zhí)行完了所有的filter,則開(kāi)始執(zhí)行servlet業(yè)務(wù)模塊servlet.service(request, response);

以上就是詳解Tomcat中Filter是怎樣執(zhí)行的的詳細(xì)內(nèi)容,更多關(guān)于Tomcat Filter執(zhí)行的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Tomcat
主站蜘蛛池模板: 国产精品亚洲一区二区在线观看 | 欧美午夜免费一级毛片 | 青青草久草在线 | 欧美禁片在线观看免费 | 亚洲最大看欧美片网站 | 国内精品自在自线视频香蕉 | 888xxxx免费视频 | 欧美在线看欧美高清视频免费 | 国产一区在线播放 | 国产青草视频在线观看 | 777免费视频 | 爱逼综合| 亚洲无线一二三四区手机 | 国产日韩高清一区二区三区 | 午夜一级片 | 最新露脸国产精品视频 | 欧美性活一级视频 | 日韩精品免费看 | 欧美日韩亚洲国产综合 | 亚欧洲精品在线视频免费观看 | 色综合夜夜嗨亚洲一二区 | 日本高清xxxx免费视频 | avv天堂| 在线播放国产真实女同事 | 国内精品视频一区二区三区 | 狠狠操影院| 亚洲国产精品人久久 | 久久精品一区二区 | a级国产 | 日韩黄色免费观看 | 一区在线观看视频 | 久久精品呦女 | 免费在线观看a级片 | 性生生活网站免费 | 91麻豆视频网站 | 黄色日韩网站 | 免费大片黄在线观看日本 | 欧美一级视频在线高清观看 | 亚洲欧美成人一区二区在线电影 | 色婷五月综激情亚洲综合 | 91视频观看免费 |