tomcat原理解析(七):执行servlet
2017-06-07 17:15
525 查看
一 概述
前面章节已经说到http的请求到达了管道处理。最后的一个管道是StandardWrapper中的管道,它最后的阀门是StandardWrapperValve,阀门中的invoke代码主要做了两件事情:1.执行过滤器链,2调用http请求servlet的service方法。
二 调用过滤器并执行servlet
这里再次贴下invoke中的代码,部分省略掉:@Override public final void invoke(Request request, Response response) throws IOException, ServletException { // Initialize local variables we may need boolean unavailable = false; Throwable throwable = null; // This should be a Request attribute... long t1=System.currentTimeMillis(); requestCount++; StandardWrapper wrapper = (StandardWrapper) getContainer();//取当前阀门对应的wrapper容器 Servlet servlet = null; Context context = (Context) wrapper.getParent();//取wrapper容器对应的父context容器 // Check for the application being marked unavailable if (!context.getAvailable()) { response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardContext.isUnavailable")); unavailable = true; } // Check for the servlet being marked unavailable //检查servlet被标记不可用 if (!unavailable && wrapper.isUnavailable()) { container.getLogger().info(sm.getString("standardWrapper.isUnavailable", wrapper.getName())); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("standardWrapper.notFound", wrapper.getName())); } unavailable = true; } // Allocate a servlet instance to process this request try { if (!unavailable) { //加载wrapper对应的servlet实例来处理此请求 //通过java反射机制来加载对象 servlet = wrapper.allocate(); } } catch (UnavailableException e) { } catch (ServletException e) { } catch (Throwable e) { } // Identify if the request is Comet related now that the servlet has been allocated boolean comet = false; if (servlet instanceof CometProcessor && request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE) { comet = true; request.setComet(true); } // Acknowledge the request try { response.sendAcknowledgement(); } catch (IOException e) { } catch (Throwable e) { } MessageBytes requestPathMB = request.getRequestPathMB(); DispatcherType dispatcherType = DispatcherType.REQUEST; if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; request.setAttribute (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, dispatcherType); request.setAttribute (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); // Create the filter chain for this request ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();//创建过滤器链工厂对象是单列的 //创建一个过滤器链对象,里面循环加载了配置中的过滤器对象 ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet); // Reset comet flag value after creating the filter chain request.setComet(false); // Call the filter chain for this request // NOTE: This also calls the servlet's service() method try { String jspFile = wrapper.getJspFile(); if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else request.removeAttribute(Globals.JSP_FILE_ATTR); if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { //TODO SERVLET3 - async ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { filterChain.doFilterEvent(request.getEvent()); request.setComet(true); } 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()) { //TODO SERVLET3 - async ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { request.setComet(true); filterChain.doFilterEvent(request.getEvent()); } else { //采用递归循环执行过滤器链中的过滤器配置,并通过反射机制加载过滤器类 filterChain.doFilter(request.getRequest(), response.getResponse()); } } } request.removeAttribute(Globals.JSP_FILE_ATTR); } catch (ClientAbortException e) { } catch (IOException e) { } catch (UnavailableException e) { } catch (ServletException e) { } catch (Throwable e) { } // Release the filter chain (if any) for this request if (filterChain != null) { if (request.isComet()) { // If this is a Comet request, then the same chain will be used for the // processing of all subsequent events. filterChain.reuse(); } else { filterChain.release(); } } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (Throwable e) { } // If this servlet has been marked permanently unavailable, // unload it and release this instance try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } } catch (Throwable e) { } long t2=System.currentTimeMillis(); long time=t2-t1; processingTime += time; if( time > maxTime) maxTime=time; if( time < minTime) minTime=time; }
上面的代码主要做了两件事
1.取当前阀门对应的wrapper容器,我们知道wrapper容器是对一个servlet信息的封装
2.创建单例的ApplicationFilterFactory对象
3.创建过滤器链ApplicationFilterChain对象
4.调用ApplicationFilterChain的doFilter方法,以递归的方式循环执行过滤器链中的过滤器
跟进到ApplicationFilterChain类的doFilter方法,代码如下:
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction<Void>() { public Void run() throws ServletException, IOException { internalDoFilter(req,res); return null; } } ); } catch( PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; else if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new ServletException(e.getMessage(), e); } } else { internalDoFilter(request,response); } }
doFilter方法中主要调用了internalDoFilter方法,代码如下:
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++];//控制过滤器链中过滤器对象获取 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); args = null; } else { filter.doFilter(request, response, this);//递归调用过滤器链中的Filter } 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 { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(request); lastServicedResponse.set(response); } support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,servlet, request, response); 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); args = null; } else { servlet.service(request, response);//执行http请求对应的servlet的servie方法 } } else { servlet.service(request, response);//执行http请求对应的servlet的servie方法 } support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response); } catch (IOException e) { } catch (ServletException e) { } catch (RuntimeException e) { } catch (Throwable e) { } finally { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(null); lastServicedResponse.set(null); } } }
internalDoFilter方法中主要干了两件事情
1.递归执行过滤器链中的过滤器
2.执行完过滤器以后,执行servlet的service方法
因为所有的servlet对象都继承HttpServlet类,跟到HttpServlet类的service方法代码如下:
@Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } }查看最后一行service(request, response);调用了当前HttpServlet类的另外一个service方法在参数类型上存在差别。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod();//取当前请求的方法名如get post //根据http请求的方法名判断是小于post方法还是get方法 if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
service方法中主要是根据请求对象(HttpServletRequest)拿到是调用的get方法和post方法。我们跟进到get方法中的代码如下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } }doGet方法中只有返回405,400异常处理的代码,这是为什么呢?
因为我们自己开发写的servlet类都会继承HttpServlet对象,同时会重写doGet和doPost方法。所以在HttpServlet的service方法中调用的doGet方法其实执行的是HttpServlet子类中的doGe方法。
三 总结
在web开发中我们定义的servlet最终都是实现了servlet接口,servlet接口是连接tomcat容器和web应用的规范。 试着扩展想想struts,springmvc应该也是实现servlet接口才会正常在tomcat中部署使用。到这里从浏览器发起http请求到如何定位并执行对应的servlet主流程已经结束,个人感觉只是知道了tomat的主体流程,很多细节的代码没有完全理解,不知道这样的阅读理解层次算不算掌握了tomcat的实现原理。
相关文章推荐
- Servlet工作原理解析2(以Tomcat为例)
- Servlet工作原理解析1(以Tomcat为例)
- 基于servlet的执行原理与生命周期(全面解析)
- TOMCAT原理以及处理HTTP请求的过程、ContextPath ServletPath
- servlet工作原理解析
- 深入学习----Servlet工作原理解析
- Servlet原理解析
- tomcat解析(-)学习如何写一个servlet服务器
- servlet工作原理解析
- servlet原理解析
- Tomcat架构、运行原理和servlet的体系结构
- JavaWeb Tomcat 配置文件解析及JSP Servlet简介
- Servlet + Tomcat 中文乱码的原理和解决方法
- Servlet + Tomcat 中文乱码的原理和解决方法
- Tomcat7 web应用的加载原理 (三) Lisener Filer Servlet的加载和调用
- oracle update执行计划原理解析与优化
- Servlet和Jsp执行解析
- Tomcat中详细配置数据源及其原理解析
- 实例解析Servlet运行原理
- Tomcat7中web应用加载原理(三)Listener、Filter、Servlet的加载和调用