zoukankan      html  css  js  c++  java
  • How Tomcat Works(十四)补充

    How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充

    FilterChain接口只有一个方法,方法声明如下:

    public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;

    在tomcat中,org.apache.catalina.core.ApplicationFilterChain类实现了该接口

    ApplicationFilterChain类采用一个私有成员变量private ArrayList filters = new ArrayList()保存ApplicationFilterConfig对象的集合,ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,封装了对Filter实例的管理

    下面是向ArrayList filters集合添加ApplicationFilterConfig实例

    void addFilter(ApplicationFilterConfig filterConfig) {
    
            this.filters.add(filterConfig);
    
        }

    setServlet()方法用于向ApplicationFilterChain对象设置当前的servlet实例

    void setServlet(Servlet servlet) {
    
            this.servlet = servlet;
    
        }

    在ApplicationFilterChain类的实现FilterChain接口方法doFilter()中,调用了其私有方法internalDoFilter(),下面是该方法的具体实现

    private void internalDoFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
    
            // Construct an iterator the first time this method is called
            if (this.iterator == null)
                this.iterator = filters.iterator();
    
            // Call the next filter if there is one
            if (this.iterator.hasNext()) {
                ApplicationFilterConfig filterConfig =
                  (ApplicationFilterConfig) iterator.next();
                Filter filter = null;
                try {
                    filter = filterConfig.getFilter();
                    support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
                                              filter, request, response);
                    filter.doFilter(request, response, this);
                    support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                              filter, request, response);
                } catch (IOException e) {
                    if (filter != null)
                        support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                                  filter, request, response, e);
                    throw e;
                } catch (ServletException e) {
                    if (filter != null)
                        support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                                  filter, request, response, e);
                    throw e;
                } catch (RuntimeException e) {
                    if (filter != null)
                        support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                                  filter, request, response, e);
                    throw e;
                } catch (Throwable e) {
                    if (filter != null)
                        support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
                                                  filter, request, response, e);
                    throw new ServletException
                      (sm.getString("filterChain.filter"), e);
                }
                return;
            }
    
            // We fell off the end of the chain -- call the servlet instance
            try {
                support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
                                          servlet, request, response);
                if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse)) {
                    servlet.service((HttpServletRequest) request,
                                    (HttpServletResponse) response);
                } else {
                    servlet.service(request, response);
                }
                support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                          servlet, request, response);
            } catch (IOException e) {
                support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                          servlet, request, response, e);
                throw e;
            } catch (ServletException e) {
                support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                          servlet, request, response, e);
                throw e;
            } catch (RuntimeException e) {
                support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                          servlet, request, response, e);
                throw e;
            } catch (Throwable e) {
                support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
                                          servlet, request, response, e);
                throw new ServletException
                  (sm.getString("filterChain.servlet"), e);
            }
    
        }

    在调用了filter.doFilter(request, response, this)方法之后,继续执行servlet的service()方法

    这里的this是ApplicationFilterChain对象自身,在我们编写的Filter实现类里面同在在执行完我们实现的过滤方法之后会继续调用FilterChain对象的void doFilter(ServletRequest request, ServletResponse response)方法,我们自定义的过滤器通常会这样实现:

    class SampleFilter implements Filter {   
          ........   
          public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)   
            throws IOException, ServletException {   
                
             //do something    
             .....   
             //request, response传递给下一个过滤器进行过滤   
             chain.doFilter(request, response);   
        }   
             
    }  

    ApplicationFilterConfig类实现了javax.servlet.FilterConfig接口,代表一个Filter容器,FilterConfig接口定义如下:

    public interface FilterConfig {    
        
        public String getFilterName(); 
    
        public ServletContext getServletContext();    
    
        public String getInitParameter(String name);   
    
        public Enumeration getInitParameterNames();
    }

    可以通过传入org.apache.catalina.Context对象和FilterDef对象(FilterDef对象用于对过滤器类的定义,包括过滤器类名、相关参数等)传给其构造函数构造一个ApplicationFilterConfig对象:

    public ApplicationFilterConfig(Context context, FilterDef filterDef)
            throws ClassCastException, ClassNotFoundException,
                   IllegalAccessException, InstantiationException,
                   ServletException {
    
            super();
            this.context = context;
            setFilterDef(filterDef);
    
        }

    ApplicationFilterConfig类的getFilter()方法返回一个javax.servlet.Filter对象,该方法负责载入并实例化一个过滤器类

    Filter getFilter() throws ClassCastException, ClassNotFoundException,
            IllegalAccessException, InstantiationException, ServletException {
    
            // Return the existing filter instance, if any
            if (this.filter != null)
                return (this.filter);
    
            // Identify the class loader we will be using
            String filterClass = filterDef.getFilterClass();
            ClassLoader classLoader = null;
            if (filterClass.startsWith("org.apache.catalina."))
                classLoader = this.getClass().getClassLoader();
            else
                classLoader = context.getLoader().getClassLoader();
    
            ClassLoader oldCtxClassLoader =
                Thread.currentThread().getContextClassLoader();
    
            // Instantiate a new instance of this filter and return it
            Class clazz = classLoader.loadClass(filterClass);
            this.filter = (Filter) clazz.newInstance();
            filter.init(this);
            return (this.filter);
    
        }

    现在,也许我们更容易理解StandardWrapperValve类中创建过滤器链createFilterChain()方法了

    private ApplicationFilterChain createFilterChain(Request request,
                                                         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 =
              new ApplicationFilterChain();
            filterChain.setServlet(servlet);
            StandardWrapper wrapper = (StandardWrapper) getContainer();
            filterChain.setSupport(wrapper.getInstanceSupport());
    
            // 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);
    //        if (debug >= 1)
    //            log("createFilterChain:  Processing " + filterMaps.length +
    //                " filter map entries");
    
            // Acquire the information we will need to match filter mappings
            String requestPath = null;
            if (request instanceof HttpRequest) {
                HttpServletRequest hreq =
                    (HttpServletRequest) request.getRequest();
                String contextPath = hreq.getContextPath();
                if (contextPath == null)
                    contextPath = "";
                String requestURI = ((HttpRequest) request).getDecodedRequestURI();
                if (requestURI.length() >= contextPath.length())
                    requestPath = requestURI.substring(contextPath.length());
            }
            String servletName = wrapper.getName();
    //        if (debug >= 1) {
    //            log(" requestPath=" + requestPath);
    //            log(" servletName=" + servletName);
    //        }
            int n = 0;
    
            // Add the relevant path-mapped filters to this filter chain
            for (int i = 0; i < filterMaps.length; i++) {
    //            if (debug >= 2)
    //                log(" Checking path-mapped filter '" +
    //                    filterMaps[i] + "'");
                if (!matchFiltersURL(filterMaps[i], requestPath))
                    continue;
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMaps[i].getFilterName());
                if (filterConfig == null) {
    //                if (debug >= 2)
    //                    log(" Missing path-mapped filter '" +
    //                        filterMaps[i] + "'");
                    ;       // FIXME - log configuration problem
                    continue;
                }
    //            if (debug >= 2)
    //                log(" Adding path-mapped filter '" +
    //                    filterConfig.getFilterName() + "'");
                filterChain.addFilter(filterConfig);
                n++;
            }
    
            // Add filters that match on servlet name second
            for (int i = 0; i < filterMaps.length; i++) {
    //            if (debug >= 2)
    //                log(" Checking servlet-mapped filter '" +
    //                    filterMaps[i] + "'");
                if (!matchFiltersServlet(filterMaps[i], servletName))
                    continue;
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMaps[i].getFilterName());
                if (filterConfig == null) {
    //                if (debug >= 2)
    //                    log(" Missing servlet-mapped filter '" +
    //                        filterMaps[i] + "'");
                    ;       // FIXME - log configuration problem
                    continue;
                }
    //            if (debug >= 2)
    //                log(" Adding servlet-mapped filter '" +
    //                     filterMaps[i] + "'");
                filterChain.addFilter(filterConfig);
                n++;
            }
    
            // Return the completed filter chain
    //        if (debug >= 2)
    //            log(" Returning chain with " + n + " filters");
            return (filterChain);
    
        }

    --------------------------------------------------------------------------- 

    本系列How Tomcat Works系本人原创 

    转载请注明出处 博客园 刺猬的温驯 

    本人邮箱: chenying998179#163.com (#改为@

    本文链接http://www.cnblogs.com/chenying99/p/3250342.html

  • 相关阅读:
    Java常量初始化后不会再去重新获取
    Intellij IDEA自动编译问题
    Tomcat关闭日志输出
    MySQL命令行导出数据库
    补充Mysql5.7用法
    Linux下安装 mysql 5.7
    IE9 表格错位bug
    Ubuntu忘记管理员密码
    实体转换计算器
    js生成二维码参数设置
  • 原文地址:https://www.cnblogs.com/chenying99/p/3250342.html
Copyright © 2011-2022 走看看