首先看一下Web应用部署初始化过程 (Web Application Deployement),官方文档说明:
Web Application Deployment
When a web application is deployed into a container, the following steps must be performed, in this order, before the web application begins processing client requests.
■ Instantiate an instance of each event listener identified by a <listener> element in the deployment descriptor.
■ For instantiated listener instances that implement ServletContextListener, call the contextInitialized() method.
■ Instantiate an instance of each filter identified by a <filter> element in the deployment descriptor and call each filter instance’s init() method.
■ Instantiate an instance of each servlet identified by a <servlet> element that includes a <load-on-startup> element in the order defined by the load-onstartup
element values, and call each servlet instance’s init() method.大致说:
Web应用部署:当一个web应用被部署到一个容器(eg.tomcat),在web应用开始处理客户端请求前,以下步骤会按顺序执行:
1.初始化应用部署描述文件中每一个listener。
2.初始化ServletContextListener实现类,调用contextInitialized()方法。
3.初始化应用部署描述文件中每一个filter,并执行每一个的init()方法。
4.按照顺序<load-on-startup>来初始化servlet,并执行init()方法。
大致总结:先初始化lisener,再filter,最后servlet
SpringMVC启动过程:
常见SpringMVC配置:<web-app> <display-name>Web Application</display-name> <!--全局变量配置--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param> <!--监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--解决乱码问题的filter--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--Restful前端控制器--> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>DispatchServlet使用说明:其类图如下:可以明显看出DispatchServlet类间接父类实现了Servlet接口,因此其本质上依旧是一个Servlet。DispatchServlet类设计很巧妙,上层父类不同程度的实现了相关接口的部分方法,并留出相关方法用于子类覆盖,将不变的部分统一实现,将变化的部分预留方法用于子类实现。DispatchServlet类初始化过程函数调用图:通过类图和相关初始化函数调用的逻辑来看,DispatchServlet的初始化过程将模板方法,其父类完成不同的统一工作,并预留出相关方法用于子类覆盖去完成不同的可变工作。DispatchServlet类的本质是Servlet,在web应用部署到容器后进行Servelt初始化时会调用相关的init(ServletConfig)方法,因此,DispatchServlet类的初始化过程也由该方法开始。其中FrameworkServlet抽象类中的initServletBean()方法、initWebApplicationContext()方法以及DispatchServlet类中的onFresh()方法。FrameworkServlet initServletBean()方法源码,该方法重写了FrameworkServlet抽象类在执行,终于,initXXXContext的字眼出现了—initWebApplicationContext()
方法会首先从ServletContext
中获取到由ContextLoaderListener
初始化完成并放进入的根容器对象引用(因为创建子容器必须将父容器作为参数传递进去),然后经过层层调用,最终在createWebApplicationContext()
中完成了容器的创建工作,该方法的主要代码如下:好了,到此就初始化完成DispatchServlet处理请求流程:/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet‘s HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet‘s installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It‘s up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we‘re processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
原文地址:https://www.cnblogs.com/jdktomcat/p/9217202.html