TomCat之Filter小析

xiaoxiao2021-02-27  552

对于做过web开发的人来说,Servlet中的过滤器肯定都不会陌生。这里我尝试着分析一下TomCat服务器中对于Filter是怎么组装的。在这之前,先把主要的几个类列一下:

Filter 过滤器接口 FilterChain 过滤器链 FilterConfig 过滤器的配置 FilterDef 过滤器的配置和描述 ApplicationFilterChain 调用过滤器链 ApplicationFilterConfig 获取过滤器 ApplicationFilterFactory 组装过滤器链

上面的这几个类是组装过滤器中比较核心的一些类。OK下面再说几个比较重要的类:

WebXml 从名字我们可以就看出来这个一个存放web.xml中内容的类 ContextConfig  一个web应用的上下文配置类 StandardContext  一个web应用上下文(Context接口)的标准实现  StandardWrapperValve   一个标准Wrapper的实现。一个上下文一般包括一个或者多个包装器,每一个包装器表示一个servlet。 在ContextConfig中会创建WebXml的实例,解析Web.xml等等一系列的工作。当然也包括实例化过滤器的动作。我们先跳过这一部分,进入到StandardWrapperValve中,因为在这个类中会进行过滤器的组装的操作,Servlet的调用。 ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);上面那句话的作用是创建一个应用过滤器链,我们进入到这个方法中看一下(在ApplicationFilterFactory这个类中): StandardContext context = (StandardContext) wrapper.getParent();//这个Context代表的是一个应用上下文的标准实现 FilterMap filterMaps[] = context.findFilterMaps();//获取FilterMaps 这个是在ContextConfig中组装的。内容是在web.xml中配置的filter // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) //如果web.xml中没有配置过滤器,则直接返回 return (filterChain); // Acquire the information we will need to match filter mappings String servletName = wrapper.getName();//获取Servlet的名字 一个StandardWrapperValue代表一个具体的Servlet // Add the relevant path-mapped filters to this filter chain for (int i = 0; i < filterMaps.length; i++) { //这里开始循环filterMaps中配置的过滤器(Servlet3.0支持注解的方式添加过滤器,这里也会包含这一部分) if (!matchDispatcher(filterMaps[i] ,dispatcher)) { //这里是过滤器支持的类型,包括 FORWARD、INCLUDE、REQUEST、ASYNC、ERROR continue; } if (!matchFiltersURL(filterMaps[i], requestPath)) //这里判断是否和请求路径相匹配 continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); //从应用上下文中查找对应的过滤器 if (filterConfig == null) { // FIXME - log configuration problem continue; } boolean isCometFilter = false; if (comet) { try { isCometFilter = filterConfig.getFilter() instanceof CometFilter; } catch (Exception e) { // Note: The try catch is there because getFilter has a lot of // declared exceptions. However, the filter is allocated much // earlier Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); } if (isCometFilter) { filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中 } } else { filterChain.addFilter(filterConfig); //添加过滤器到过滤器链中 } }在下面还有一段和这一段类似的组装过滤器的内容,我们不再分析。我们看看addFilter这个方法中做了什么: void addFilter(ApplicationFilterConfig filterConfig) { // Prevent the same filter being added multiple times for(ApplicationFilterConfig filter:filters) if(filter==filterConfig)//去掉重复的过滤器配置 这里用的是 == return; if (n == filters.length) {//对过滤器配置数组扩容 一次括十个长度 ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters, 0, newFilters, 0, n); filters = newFilters; } filters[n++] = filterConfig; //加入到数组中 }下面我们再回到org.apache.catalina.core.StandardWrapperValve这个类的invoke方法中: // Call the filter chain for this request 注释写的很清楚 调用过滤器链 // NOTE: This also calls the servlet's service() method //同时也会调用servlet的service方法 try { if ((servlet != null) && (filterChain != null)) { //如果存在过滤器链 // Swallow output if needed if (context.getSwallowOutput()) { //需要吞咽输出 (不知道是什么东西) try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { // Servlet3.0的新特性 ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { //这里不太清楚 filterChain.doFilterEvent(request.getEvent()); } 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()) { ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { filterChain.doFilterEvent(request.getEvent()); } else { //执行过滤器 filterChain.doFilter (request.getRequest(), response.getResponse()); } }下面我们进入到org.apache.catalina.core.ApplicationFilterChain的doFilter方法中这个方法其实是调用的internalDoFilter(request,response);这个方法,我们直接进入到这个方法中: private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { // n代表的是过滤器链中有多少个过滤器 pos代表当前执行到哪个过滤器了 ApplicationFilterConfig filterConfig = filters[pos++]; //获取要执行的过滤器配置 Filter filter = null; try { filter = filterConfig.getFilter(); //要执行的过滤器 support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); //过滤器执行前的事件 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);//执行过滤器 这里可以看到最后传的参数是this 以达到循环调用的目的 } support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response); //过滤器执行后的事件我们继续往下看 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); } support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, servlet, request, response); // Service执行前的事件 if (request.isAsyncSupported() && !support.getWrapper().isAsyncSupported()) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } // Use potentially wrapped request from this point if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) { if( 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); //调用service的方法 } } else { servlet.service(request, response); //调用service的方法 } support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response);//service执行后的方法OK,上面就是大致的一个过滤器链组装和调用的过程。下面我把和Filter相关的一些类抽取了出来,以便能在项目中使用到这种模式-责任链模式。 Filter:过滤器 public interface Filter { /** * 要执行过滤器 * * @param request * @param response * @param chain * @throws IOException */ void doFilter(Object request, Object response, FilterChain chain) throws IOException; void destory(); } FilterChain:过滤器链 public interface FilterChain { /** * 过滤器链,执行过滤器 * @param request * @param response * @throws IOException */ void doFilter(Object request, Object response) throws IOException; }ApplicationFilterConfig:过滤器的一些特殊配置 public class ApplicationFilterConfig { /** * 设置过滤器 */ private Filter filter; public Filter getFilter() { return filter; } public ApplicationFilterConfig(Filter filter) { this.filter = filter; } }ApplicationFilterChain:组装过滤器链,调用过滤器 public class ApplicationFilterChain implements FilterChain { /** * 执行到哪一个过滤器了 */ private int pos = 0; /** * 一共有组装了多少个过滤器 */ private int n = 0; /** * 执行完过滤器之后执行的处理类 */ private Servlet servlet; /** * 过滤器数组 */ private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; /** * 每次增加的长度 */ public static final int INCREMENT = 10; /** * 过滤器链,执行过滤器 * * @param request * @param response * @throws IOException */ @Override public void doFilter(Object request, Object response) throws IOException { //@TODO 这里可以写一些逻辑处理 internalDoFilter(request, response); } public void internalDoFilter(Object request, Object response) throws IOException { if (pos < n) { //过滤器的处理 ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = filterConfig.getFilter(); filter.doFilter(request,response,this); return; } servlet.service(request,response); } /** * 添加过滤器 * @param filterConfig */ public void addFilter(ApplicationFilterConfig filterConfig){ //过滤掉重复的Filter for(int i=0;i<filters.length;i++){ if(Objects.equals(filters[i], filterConfig)){ return; } } //数组扩容 if( n == filters.length){ ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters,0,newFilters,0,n); filters = newFilters; } filters[n++] = filterConfig; } public void setServlet(Servlet servlet) { this.servlet = servlet; } public void release() { for (int i = 0; i < n; i++) { filters[i] = null; } n = 0; pos = 0; servlet = null; } }ApplicationFilterFactory:创建过滤器链 public final class ApplicationFilterFactory { /** * 创建过滤器链,每个请求都会调用 * @param request * @param wrapper * @param servlet */ public static ApplicationFilterChain createFilterChain(Object request, Object wrapper, Servlet servlet){ ApplicationFilterChain applicationFilterChain = new ApplicationFilterChain(); //设置Filter ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(new FirProcessFilter()); applicationFilterChain.addFilter(filterConfig); filterConfig = new ApplicationFilterConfig(new SecProcessFilter()); applicationFilterChain.addFilter(filterConfig); return applicationFilterChain; } }

转载请注明原文地址: https://www.6miu.com/read-586.html

最新回复(0)