Servlet的生命周期以及在Spring MVC中调用流程
接触Web时间比较久,虽然知道Servlet的生命周期但是理解却还是不够,今天刚好debug代码涉及这块就利用余下时间研究了一下。
Servlet的生命周期以及处理浏览器请求的过程。Servlet接口中定义的方法有:
而init -> service -> destory刚好就是servlet的生命周期。通常当web容器(即web服务器,例如tomct等)启动时候回根据配置文件进行加载servlet,加载servlet过程就是初始化servlet的过程。
由web容器进行调用生命周期init方法进行初始化。初始化完成便可以进行处理浏览器发送的请求了。
当浏览器向Web容器发送请求时候便由Web容器调用Servelt的service方法(此处实现是HttpServlet的service方法)进行处理浏览器请求。HttpService的service方法关键源码实现如下:
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- String method = req.getMethod();
- //判断客户端的请求是get、post、...
- if (method.equals(METHOD_GET)) {
- long lastModified = getLastModified(req);
- if (lastModified == -1) {
- doGet(req, resp);
- } else {
- long ifModifiedSince;
- try {
- ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
- } catch (IllegalArgumentException iae) {
- ifModifiedSince = -1;
- }
- if (ifModifiedSince < (lastModified / 1000 * 1000)) {
- 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);//处理post请求
- } 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 {
- 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);
- }
- }
本例以post请求进行源码跟踪,处理post请求调用doPost方法。此处回顾一下我们一般写一个servlet时候需要的步骤了,我们都是自己定义一个Servlet类然后一般都是实现doPost和doGet方法,回顾到此就可以回到本文了,本例中调用的doPost方法就是调用我们自己实现的doPost方法,这个流程下来就完成了浏览器的请求。而对于Servlet的销毁由Web容器调用destory方法进行销毁。
Spring MVC中DispatherServlet的继承结构:
在使用Spring MVC进行开发时候,在web.xml中需要配置DispatherServlet,让Web容器启动时候加载Servlet。通过继承结构可以发现DispatherServlet是HttpServlet的子类。
当浏览器进行请求时候Web容器会调用DispatherServlet的service方法,DispatherServlet的service方法在父类FrameWorkServlet中实现;FrameWorkServlet#service方法源码如下:
- /**
- * Override the parent class implementation in order to intercept PATCH requests.
- */
- @Override
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
- if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
- processRequest(request, response);
- }
- else {
- super.service(request, response);
- }
- }
最后调用super.service调用HttpServlet#service方法,进行判断请求的方法是get、post还是...然后调用对应的doXXX方法,此处的doXXX方法在FrameWorkServlet中实现(FrameWorkServlet是框架实现的一个Servlet,与正常Servlet开发的servlet类似)。
org.springframework.web.servlet.FrameworkServlet#doServiceorg.springframework.web.servlet.FrameworkServlet#doPost源码如下:
- @Override
- protected final void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- processRequest(request, response);
- }
org.springframework.web.servlet.FrameworkServlet#processRequest源码如下:
- protected final void processRequest(HttpServletRequest request, HttpServletResponse response) //DispatcherServlet的processRequst方法在FrameWork中实现
- throws ServletException, IOException {
- long startTime = System.currentTimeMillis();
- Throwable failureCause = null;
- LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
- LocaleContext localeContext = buildLocaleContext(request);
- RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
- WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
- asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
- initContextHolders(request, localeContext, requestAttributes);
- try {
- doService(request, response); //重点
- }
- catch (ServletException ex) {
- failureCause = ex;
- throw ex;
- }
- catch (IOException ex) {
- failureCause = ex;
- throw ex;
- }
- catch (Throwable ex) {
- failureCause = ex;
- throw new NestedServletException("Request processing failed", ex);
- }
- finally {
- resetContextHolders(request, previousLocaleContext, previousAttributes);
- if (requestAttributes != null) {
- requestAttributes.requestCompleted();
- }
- if (logger.isDebugEnabled()) {
- if (failureCause != null) {
- this.logger.debug("Could not complete request", failureCause);
- }
- else {
- if (asyncManager.isConcurrentHandlingStarted()) {
- logger.debug("Leaving response open for concurrent processing");
- }
- else {
- this.logger.debug("Successfully completed request");
- }
- }
- }
- publishRequestHandledEvent(request, response, startTime, failureCause);
- }
- }
org.springframework.web.servlet.DispatcherServlet#doService源码:
- @Override
- protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
- if (logger.isDebugEnabled()) {
- String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
- logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
- " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
- }
- // Keep a snapshot of the request attributes in case of an include,
- // to be able to restore the original attributes after the include.
- Map<String, Object> attributesSnapshot = null;
- if (WebUtils.isIncludeRequest(request)) {
- attributesSnapshot = new HashMap<String, Object>();
- Enumeration<?> attrNames = request.getAttributeNames();
- while (attrNames.hasMoreElements()) {
- String attrName = (String) attrNames.nextElement();
- if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
- attributesSnapshot.put(attrName, request.getAttribute(attrName));
- }
- }
- }
- // Make framework objects available to handlers and view objects.
- request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
- request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
- request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
- request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
- FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
- if (inputFlashMap != null) {
- request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
- }
- request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
- request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
- try {
- doDispatch(request, response); //重点
- }
- finally {
- if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
- // Restore the original attribute snapshot, in case of an include.
- if (attributesSnapshot != null) {
- restoreAttributesAfterInclude(request, attributesSnapshot);
- }
- }
- }
- }
最后调用doDispatch(request, response)方法完成处理(后续代码有时间在跟踪)。
过程总结:
Servlet的生命周期以及在Spring MVC中调用流程的更多相关文章
- Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用
Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/1019 ...
- Spring,SpringMVC,MyBatis,Hibernate,Servlet的生命周期,jsp有哪些内置对象,Tomcat,Cookie和Session的作用以及区别,oracle,MYSQL等面试题总结
1. 什么是Spring,谈谈你对Spring的理解 Spring是我们JAVA开发人员在搭建后台时选用的一个轻量级的开源框架,Spring框架目前也是功能丰富,十分优秀企业级采用最多的一个框架. S ...
- Spring Bean的生命周期、Spring MVC的工作流程、IOC,AOP
1.Spring Bean的生命周期? (1)构造方法实例化bean. (2)构造方法设置对象属性. (3)是否实现aware接口,三种接口(BeanNameAware,BeanFactoryAwar ...
- Servlet的生命周期及工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...
- Servlet的生命周期
Servlet的生命周期 Servlet的生命周期是由tomcat服务器来控制的. 1 构造方法: 创建servlet对象的时候调用.默认情况下,第一访问servlet就会创建servlet对象只创建 ...
- Servlet的生命周期+实现方式
1.Servlet的生命周期: (1)被创建: 默认情况下,Servlet第一次被访问时,被服务器创建.会调用init()方法. 一个 ...
- Servlet基础(二) Servlet的生命周期
Servlet基础(二) Servlet的生命周期 Servlet的生命周期可以分为三个阶段: 1.初始化阶段 2.响应客户请求阶段 3.终止阶段 Servlet的初始化阶段 在下列时刻Servlet ...
- JSP Servlet WEB生命周期
[转载] JavaWeb的生命周期是由Servlet容器来控制的总的来说分为三个阶段1.启动阶段:加载web应用相关数据,创建ServletContext对象,对Filter和servlet进行初始化 ...
- servlet的生命周期与运行时的线程模型
第 14 章 生命周期 注意 讲一下servlet的生命周期与运行时的线程模型,对了解servlet的运行原理有所帮助,这样才能避免一些有冲突的设计. 如果你不满足以下任一条件,请继续阅读,否则请跳过 ...
随机推荐
- Ajax之跨域请求
一.引子 我现在开启了两个django项目,分别叫Demo1和Demo2,Demo1中有一个路径‘http://127.0.0.1:8000/index/’,对应的视图是index视图返回一个inde ...
- pip更新到18版本后使用pycharm更新问题:module 'pip' has no attribute 'main'
今天升级pip到18.0版本后更新模块时出现错误 分析报错信息可知,问题出在packaging_tool.py文件的213行和109行,找到具体的代码,如下 # 109行函数 def do_insta ...
- anaconda更新库命令
输入y更新库
- 通过swagger将API业务版本号与Gitlab代码版本号绑定
1.调用Gitlab API获取项目commit ID 2.编辑 Swagger2.java @Configuration @EnableSwagger2 @EnableWebMvc public c ...
- Easyui-textbox得到焦点方法
得到焦点是我们在编写前台时经常使用到的,为了提高用户的体验度,话不多说直接上代码. jsp页面: <div class="box_xian"> <span cla ...
- Linux常用基本命令:tr-替换或者删除字符
tr命令 作用:从标准输入中替换,缩减或者删除字符,并将结果输出到标准输出 格式:tr [option] [set1] [set2] tr [选项] [字符1] [字符2] 把y替换m, o替换e,并 ...
- HDU5543(SummerTrainingDay03-O DP)
Pick The Sticks Time Limit: 15000/10000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others ...
- JSON方式封装通信接口
1.封装通信接口数据的方法 2. 案例:生成json 注意:json_encode() 只能接收utf-8数据 测试: <?php $arr = array( 'id'=>1, 'name ...
- userDefineFunc.js
var scareMe = function(){ console.log("cynthia") scareMe = function(){ console.log("w ...
- 3038 3n+1问题
3038 3n+1问题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 白银 Silver 题解 题目描述 Description 3n+1问题是一个简单有趣而又没有 ...