Tomcat源码阅读三:过滤器实现

来源:互联网 发布:win7禁止安装任何软件 编辑:程序博客网 时间:2024/06/15 15:16
这里省略各种tomcat的初始化和启动过程,简略说下,就是Bootstrap中,初始化HttpConnector类,初始化父容器StandardContext,子容器StandartWapper,以及一些生命周期,然后各种关联赋值,最后调用连接器的初始化方法,然后调用start方法,单一启动模式开启。这里,连接器有serverSocket等待接受请求,同时存在HttpProcess类,和前面一样,线程之间等待,交互,Process得到socet,assign(socket),socket给了处理器,处理器的run方法执行此行  process(socket);处理socket对象,HttpProcessor处理器对象拥有request和response全局变量,在处理器这里,解析了socket之后初始化了request和response对象。然后再处理器的process方法中调用 connector.getContainer().invoke(request, response);父容器启动,一直启动到子容器。这里说下容器关系,父容器是StandadContext,子容器是StandartWapper,它们都继承自ContainerBase类,实现了Context接口,都拥有自己的PipeLine对象,pipeLine对象都拥有自己的处理阀,父容器的基础阀是StandartContextValve,子容器的基础阀是StandardWapperValve等。先说下pipeline的启动,StandartContext继承自ContainerBase类,此类拥有pipeline对象和basic阀和一个Valve阀数组,首先父容器启动,然后调用pipeline的invoke方法,管道启动后,会调用各个阀进行servlet的处理,首先调用Valve数组,若此阀数组为空,则调用basic阀,若basic阀也为空则抛出异常,这里有一个细节就是,Valve阀会按数组下标++顺序执行,执行完后就不在执行Valve阀数组,转而执行basic阀。StandardContext的invoke(   )方法调用super.invoke(request, response);即ContainerBase的invoke()方法,  ContainerBase中的invoke方法调用管道的invoke(  )方法pipeline.invoke(request, response);看下pipeline的启动invok()方法,在管道的invoke方法中初始化了StandardPipeLine的一个内部类  (new StandardPipelineValveContext()).invokeNext(request, response);看下invokeNext方法,内容如下:
         public void invokeNext(Request request, Response response)
            throws IOException, ServletException {

            int subscript = stage;
            stage = stage + 1;

            // Invoke the requested Valve for the current request thread
            if (subscript < valves.length) {
                valves[subscript].invoke(request, response, this);
            } else if ((subscript == valves.length) && (basic != null)) {
                basic.invoke(request, response, this);
            } else {
                throw new ServletException
                    (sm.getString("standardPipeline.noValve"));
            }
        }
注:一个wrapper每次对应一个servlet,wrapper的pipeline每次只会执行一个阀,阀数组下标每次+1
 
     这里的basic阀就是StandardContextValve,在这个阀里面,获取子容器wapper,调用    wrapper.invoke(request, response);在wrapper的invoke里,原理和父容器一样,只不过basic阀是StandardWrapperValve类,在基础阀的invoke( )方法中,调用了容器wrapper的allocate方法  servlet = wrapper.allocate();获取servlet实例,然后执行   ApplicationFilterChain filterChain =
            createFilterChain(request, servlet);这里就到了本文要谈的过滤器的实现。在没有发生异常的前提下,在向请求段发送了ack确认后,就会初始化对象   ApplicationFilterChain filterChain =  createFilterChain(request, servlet);简略说下过滤器的一些实现类,ApplicationFilterChain 代表的是一个过滤器链,FilterDef类代表了一个为web应用定义的过滤器实体,此类并没有太多逻辑方法,只包含一些属性如description描述,displayName和filterClass、filterName,filterClass是过滤器类的全限定名,以及这些属性的get 、set方法。所以说FilterDef并不包含过滤器要实现的逻辑,从某种意义上来说,它只是对开发者展示了一个过滤器定义(包含名字、描述等)。这里还有一个ApplicationFilterConfig类,此类可以理解为过滤器的控制类,包含FilterDef过滤器定义类, ApplicationFilterConfig的getFilter方法返回一个过滤器,方法内部通过类加载器加载FilterDef中的类全限定名。所加载的才是真正的过滤器实现类Filter类。在StandardWrapperValve的invoke( )方法中;  if ((servlet != null) && (filterChain != null)) {
                filterChain.doFilter(sreq, sres);
            } 调用filterChain.doFilter(sreq, sres);


看下doFilter方法  public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

        if( System.getSecurityManager() != null ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            try {
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedExceptionAction()
                    {
                        public Object run() throws ServletException, IOException {
                            internalDoFilter(req,res);
                            return null;
                        }
                    }
                );
            }
这里 java.security.AccessController.doPrivileged以及内部类是让internalDoFilter(req,res)跳过权限检查直接执行!
  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);
        }

    }
这里过滤器数组存放的是ApplicationFilterConfig类,iterator = filters.iterator();、
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);

执行了doFilter方法时,触发监听器事件,调用然后调用servlet的service方法传入request和response。
这里有个疑问就是,为什么过滤器没有循环调用,而只是next(  )了一次?为了解决这个疑问,查了下百度,下面是参考博客:



     Tomcat的过滤器主要由Filter、FilterChain组成,FilterChain包含一个Filter数组.当Wrapper执行FilterChain的doFilter(request,response)方法时,FilterChain首先调用第一个Filter的doFilter(request,response,filterchain)方法,当第一个filter做完过滤操作后,它又会调用filterchain的doFilter方法,此时filterchain的当前filter已变为第二个filter,第二个filter又执行dofilter方法,依此类推,直至所有过滤器都执行完毕 

1.接口 
Java代码  收藏代码
  1. public interface Filter {  
  2.         .....         
  3.         //执行过滤  
  4.         public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;  
  5.   
  6. }  
  7.   
  8. public interface FilterChain {  
  9.     public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;  
  10. }  


2.实现例子 
Java代码  
  1. class ApplicationFilterChain implements FilterChain {  
  2.      
  3.    //pos为当前filter的所在位置,n为filters数组的长度  
  4.    if (pos < n) {  
  5.             //pos++执行后,把filterchain的当前filter指向下一个  
  6.             ApplicationFilterConfig filterConfig = filters[pos++];  
  7.             Filter filter = null;  
  8.             try {  
  9.                 filter = filterConfig.getFilter();  
  10.   
  11.                 //filter执行过滤操作  
  12.                 filter.doFilter(request, response, this);  
  13.             }  
  14.             ...  
  15.    }  
  16. }  
  17.   
  18.   
  19. class SampleFilter implements Filter {  
  20.       ........  
  21.       public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)  
  22.         throws IOException, ServletException {  
  23.            
  24.          //do something   
  25.          .....  
  26.          //request, response传递给下一个过滤器进行过滤  
  27.          chain.doFilter(request, response);  
  28.     }  
  29.         
  30. }  

0 0
原创粉丝点击