tomcat解析(十九)对客户请求的处理3
2010-02-09 18:14
387 查看
下面是StandardContextValve的invoke方法内容
<1>对于路径中直接访问META-INF或WEB-INF目录下资源的,直接返回404错误
<2>如果此时当前Context正在reload,则线程暂停并设置最新的ClassLoader;如果匹配到的wrapper处理不存在,则返回404错误,若wrapper处于不可用的状态,重新获取,因为可以处理reload的过程中
<3>触发该Context下已注册的ServletContextAttributeListener,ServletRequestAttributeListener,ServletRequestListener及HttpSessionAttributeListener的contextInitialized事件,在第四步后还触发其requestDestroyed事件,这里没有注册这几个监听器,暂时不讲.
<4>调用对应wrapper的方法:wrapper.getPipeline().getFirst().invoke(request, response);
依然可以根据StandardWrapper的构造方法看到将调用的是StandardWrapperValve的invoke方法
内容大概有
1.查看当前context及wrapper对象是否处理于unavailable状态,主要是服务器关闭或重启问题
2.状态可用,分配实例化及初始化当前Wrapper对应的Servlet对象,servlet = wrapper.allocate()
3.以当前请求,servlet及wrapper对象为参数创建对应的ApplicationFilterChain对象(实现了FilterChain接口:Filter将使用到),此时会将当前Context里与该request对应的Filter加到ApplicationFilterChain里,无特殊顺序,因此将是按照web.xml里的声明顺序来的
4.调用ApplicationFilterChain对象的doFilterEvent或doFilter方法(两者如何区别仍未知,后续再说),java Web开发很多都在此部分内容;doFilter方法里主要又是调用了internalDoFilter方法进行处理
3.对实例化的Servlet及ApplicationFilterChain对象进行资源回收
ApplicationFilterChain.internalDoFilter内容大概如下:
1.调用所持有的第一个Filter的doFilter方法,以request,response及自身为参数
设想开发者编写了两个Filter,在过滤请求的时候便会执行上面这一段代码来调用第一个Filter,如果在第一个Filter里又调用了FilterChain.doFilter,则又会调用上面这一段代码,而此时pos已自加1,因此将会调用第二个Filter处理类,依次类推直到最后的Filter的doFilter方法执行完,之后便会返回前一个Filter继续运行其调用FilterChain.doFilter之后的代码,又依次类推直到第一个Filter.当然这部分是Filter的执行,我们都知道还有一个Servlet会执行,那到底Servlet是什么时候执行呢?依然是ApplicationFilterChain.internalDoFilter,当所有的Filter都已执行,并且在最后一个Filter又调用了FilterChain.doFilter,再来到这个方法时则不会再执行上面列出的代码,而是运行下面这段代码:
可以看到在最后的Filter再执行FilterChain.doFilter的时候将会执行请求对应的Servlet类的service方法,这也是我们早已知道的一个事实,现在只是揭开了其实现的面纱.当然既然还有Servlet需要执行,那上面的一段话应该是这样描述才对,依次类推直到Servlet执行完成后又返回其前面的Filter,再依次类推直到第一个Filter.这个实现其实与之后我们看过的PipeLine方式实现上异曲同工,但个人认为相对于Pipeline的实现,Filter的开发键较偏面向过程,而Pipeline的实现较OO(if
u know what i mean:),如之前所说,在Struts2的拦截器上也是相似的模式,但也是OO模式的,所以我在猜想编写Filter实现的开发人员可能拥有较长时间的面向过程编程资历,所以一下子比较难转换过来(纯属个人看法:)
另有一点需要注意的,客户端的返回是什么时候给的呢?如果我们不用JSP写界面,直接用Servlet或许比较明显地看出,我们一般都会写
PrintWriter out = Response.getWriter();
out.print();
out.close();
这里即会打开一个客户请求的返回结果流,然后将结果写入,因此即使我们有Filter可对返回结果进行处理,但事实在Servlet返回之后的处理是不会表现到客户端的.在实际的MVC框架如STRUTS2,SPRING MVC中,使用了JSP做为输出,但情况也是如此的
<1>对于路径中直接访问META-INF或WEB-INF目录下资源的,直接返回404错误
MessageBytes requestPathMB = request.getRequestPathMB(); if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/META-INF")) || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { notFound(response); return; }
<2>如果此时当前Context正在reload,则线程暂停并设置最新的ClassLoader;如果匹配到的wrapper处理不存在,则返回404错误,若wrapper处于不可用的状态,重新获取,因为可以处理reload的过程中
// Wait if we are reloading boolean reloaded = false; while (context.getPaused()) { reloaded = true; try { Thread.sleep(1000); } catch (InterruptedException e) { ; } } // Reloading will have stopped the old webappclassloader and // created a new one if (reloaded && context.getLoader() != null && context.getLoader().getClassLoader() != null) { Thread.currentThread().setContextClassLoader( context.getLoader().getClassLoader()); } // Select the Wrapper to be used for this Request Wrapper wrapper = request.getWrapper(); if (wrapper == null) { notFound(response); return; } else if (wrapper.isUnavailable()) { // May be as a result of a reload, try and find the new wrapper wrapper = (Wrapper) container.findChild(wrapper.getName()); if (wrapper == null) { notFound(response); return; } }
<3>触发该Context下已注册的ServletContextAttributeListener,ServletRequestAttributeListener,ServletRequestListener及HttpSessionAttributeListener的contextInitialized事件,在第四步后还触发其requestDestroyed事件,这里没有注册这几个监听器,暂时不讲.
<4>调用对应wrapper的方法:wrapper.getPipeline().getFirst().invoke(request, response);
依然可以根据StandardWrapper的构造方法看到将调用的是StandardWrapperValve的invoke方法
内容大概有
1.查看当前context及wrapper对象是否处理于unavailable状态,主要是服务器关闭或重启问题
2.状态可用,分配实例化及初始化当前Wrapper对应的Servlet对象,servlet = wrapper.allocate()
3.以当前请求,servlet及wrapper对象为参数创建对应的ApplicationFilterChain对象(实现了FilterChain接口:Filter将使用到),此时会将当前Context里与该request对应的Filter加到ApplicationFilterChain里,无特殊顺序,因此将是按照web.xml里的声明顺序来的
4.调用ApplicationFilterChain对象的doFilterEvent或doFilter方法(两者如何区别仍未知,后续再说),java Web开发很多都在此部分内容;doFilter方法里主要又是调用了internalDoFilter方法进行处理
3.对实例化的Servlet及ApplicationFilterChain对象进行资源回收
ApplicationFilterChain.internalDoFilter内容大概如下:
1.调用所持有的第一个Filter的doFilter方法,以request,response及自身为参数
// Call the next filter if there is one if (pos < n) { //n为filter的个数 ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; try { filter = filterConfig.getFilter(); support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); 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); args = null; } else { 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; }
设想开发者编写了两个Filter,在过滤请求的时候便会执行上面这一段代码来调用第一个Filter,如果在第一个Filter里又调用了FilterChain.doFilter,则又会调用上面这一段代码,而此时pos已自加1,因此将会调用第二个Filter处理类,依次类推直到最后的Filter的doFilter方法执行完,之后便会返回前一个Filter继续运行其调用FilterChain.doFilter之后的代码,又依次类推直到第一个Filter.当然这部分是Filter的执行,我们都知道还有一个Servlet会执行,那到底Servlet是什么时候执行呢?依然是ApplicationFilterChain.internalDoFilter,当所有的Filter都已执行,并且在最后一个Filter又调用了FilterChain.doFilter,再来到这个方法时则不会再执行上面列出的代码,而是运行下面这段代码:
// We fell off the end of the chain -- call the servlet instance try { if (Globals.STRICT_SERVLET_COMPLIANCE) { lastServicedRequest.set(request); lastServicedResponse.set(response); } support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, servlet, request, response); 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); args = null; } else { 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); } finally { if (Globals.STRICT_SERVLET_COMPLIANCE) { lastServicedRequest.set(null); lastServicedResponse.set(null); } }
可以看到在最后的Filter再执行FilterChain.doFilter的时候将会执行请求对应的Servlet类的service方法,这也是我们早已知道的一个事实,现在只是揭开了其实现的面纱.当然既然还有Servlet需要执行,那上面的一段话应该是这样描述才对,依次类推直到Servlet执行完成后又返回其前面的Filter,再依次类推直到第一个Filter.这个实现其实与之后我们看过的PipeLine方式实现上异曲同工,但个人认为相对于Pipeline的实现,Filter的开发键较偏面向过程,而Pipeline的实现较OO(if
u know what i mean:),如之前所说,在Struts2的拦截器上也是相似的模式,但也是OO模式的,所以我在猜想编写Filter实现的开发人员可能拥有较长时间的面向过程编程资历,所以一下子比较难转换过来(纯属个人看法:)
另有一点需要注意的,客户端的返回是什么时候给的呢?如果我们不用JSP写界面,直接用Servlet或许比较明显地看出,我们一般都会写
PrintWriter out = Response.getWriter();
out.print();
out.close();
这里即会打开一个客户请求的返回结果流,然后将结果写入,因此即使我们有Filter可对返回结果进行处理,但事实在Servlet返回之后的处理是不会表现到客户端的.在实际的MVC框架如STRUTS2,SPRING MVC中,使用了JSP做为输出,但情况也是如此的
相关文章推荐
- tomcat解析(十八)对客户请求的处理2
- 解读Tomcat(三):请求处理解析Part_1
- tomcat解析(十六)对客户端请求的处理
- 解析Tomcat处理请求的类Connector<1>
- Tomcat请求处理过程(Tomcat源码解析五)
- Tomcat请求处理过程(Tomcat源代码解析五)
- tomcat原理解析(五):http请求处理
- Tomcat请求处理过程(Tomcat源码解析五)
- tomcat设置为UTF-8,解析GBK编码的UTL请求,中文乱码处理
- 客户请求的处理:表单数据
- Tomcat 请求过程源码解析(二)
- Tomcat请求处理流程
- jquery解析JSON数据,异步请求,快速准确处理
- Tomcat与Struts2处理请求过程 Hibernate基本原理 Spring基本原理
- Spring mvc请求处理流程详解(一)之视图解析
- 写给自己的网络请求解析 返回数组和字典类型不同的处理方法
- How Tomcat works — 六、tomcat处理请求
- Netty 4源码解析:请求处理
- tomcat 解析(二)-消息处理过程
- Tomcat结构及处理用户请求