接触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方法关键源码实现如下:

  1. protected void service(HttpServletRequest req, HttpServletResponse resp)
  2. throws ServletException, IOException {
  3.  
  4. String method = req.getMethod();
  5. //判断客户端的请求是get、post、...
  6. if (method.equals(METHOD_GET)) {
  7. long lastModified = getLastModified(req);
  8. if (lastModified == -1) {
  9. doGet(req, resp);
  10. } else {
  11. long ifModifiedSince;
  12. try {
  13. ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
  14. } catch (IllegalArgumentException iae) {
  15. ifModifiedSince = -1;
  16. }
  17. if (ifModifiedSince < (lastModified / 1000 * 1000)) {
  18. maybeSetLastModified(resp, lastModified);
  19. doGet(req, resp);
  20. } else {
  21. resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
  22. }
  23. }
  24.  
  25. } else if (method.equals(METHOD_HEAD)) {
  26. long lastModified = getLastModified(req);
  27. maybeSetLastModified(resp, lastModified);
  28. doHead(req, resp);
  29.  
  30. } else if (method.equals(METHOD_POST)) {
  31. doPost(req, resp);//处理post请求
  32.  
  33. } else if (method.equals(METHOD_PUT)) {
  34. doPut(req, resp);
  35.  
  36. } else if (method.equals(METHOD_DELETE)) {
  37. doDelete(req, resp);
  38.  
  39. } else if (method.equals(METHOD_OPTIONS)) {
  40. doOptions(req,resp);
  41.  
  42. } else if (method.equals(METHOD_TRACE)) {
  43. doTrace(req,resp);
  44.  
  45. } else {
  46.  
  47. String errMsg = lStrings.getString("http.method_not_implemented");
  48. Object[] errArgs = new Object[1];
  49. errArgs[0] = method;
  50. errMsg = MessageFormat.format(errMsg, errArgs);
  51. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
  52. }
  53. }

本例以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方法源码如下:

  1. /**
  2. * Override the parent class implementation in order to intercept PATCH requests.
  3. */
  4. @Override
  5. protected void service(HttpServletRequest request, HttpServletResponse response)
  6. throws ServletException, IOException {
  7.  
  8. HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
  9. if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
  10. processRequest(request, response);
  11. }
  12. else {
  13. super.service(request, response);
  14. }
  15. }

  

最后调用super.service调用HttpServlet#service方法,进行判断请求的方法是get、post还是...然后调用对应的doXXX方法,此处的doXXX方法在FrameWorkServlet中实现(FrameWorkServlet是框架实现的一个Servlet,与正常Servlet开发的servlet类似)。

org.springframework.web.servlet.FrameworkServlet#doServiceorg.springframework.web.servlet.FrameworkServlet#doPost源码如下:

  1. @Override
  2. protected final void doPost(HttpServletRequest request, HttpServletResponse response)
  3. throws ServletException, IOException {
  4.  
  5. processRequest(request, response);
  6. }

org.springframework.web.servlet.FrameworkServlet#processRequest源码如下:

  1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response) //DispatcherServlet的processRequst方法在FrameWork中实现
  2. throws ServletException, IOException {
  3.  
  4. long startTime = System.currentTimeMillis();
  5. Throwable failureCause = null;
  6.  
  7. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  8. LocaleContext localeContext = buildLocaleContext(request);
  9.  
  10. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  11. ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
  12.  
  13. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  14. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
  15.  
  16. initContextHolders(request, localeContext, requestAttributes);
  17.  
  18. try {
  19. doService(request, response); //重点
  20. }
  21. catch (ServletException ex) {
  22. failureCause = ex;
  23. throw ex;
  24. }
  25. catch (IOException ex) {
  26. failureCause = ex;
  27. throw ex;
  28. }
  29. catch (Throwable ex) {
  30. failureCause = ex;
  31. throw new NestedServletException("Request processing failed", ex);
  32. }
  33.  
  34. finally {
  35. resetContextHolders(request, previousLocaleContext, previousAttributes);
  36. if (requestAttributes != null) {
  37. requestAttributes.requestCompleted();
  38. }
  39.  
  40. if (logger.isDebugEnabled()) {
  41. if (failureCause != null) {
  42. this.logger.debug("Could not complete request", failureCause);
  43. }
  44. else {
  45. if (asyncManager.isConcurrentHandlingStarted()) {
  46. logger.debug("Leaving response open for concurrent processing");
  47. }
  48. else {
  49. this.logger.debug("Successfully completed request");
  50. }
  51. }
  52. }
  53.  
  54. publishRequestHandledEvent(request, response, startTime, failureCause);
  55. }
  56. }

 org.springframework.web.servlet.DispatcherServlet#doService源码:

  1. @Override
  2. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  3. if (logger.isDebugEnabled()) {
  4. String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
  5. logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
  6. " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  7. }
  8.  
  9. // Keep a snapshot of the request attributes in case of an include,
  10. // to be able to restore the original attributes after the include.
  11. Map<String, Object> attributesSnapshot = null;
  12. if (WebUtils.isIncludeRequest(request)) {
  13. attributesSnapshot = new HashMap<String, Object>();
  14. Enumeration<?> attrNames = request.getAttributeNames();
  15. while (attrNames.hasMoreElements()) {
  16. String attrName = (String) attrNames.nextElement();
  17. if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
  18. attributesSnapshot.put(attrName, request.getAttribute(attrName));
  19. }
  20. }
  21. }
  22.  
  23. // Make framework objects available to handlers and view objects.
  24. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  25. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  26. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  27. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
  28.  
  29. FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
  30. if (inputFlashMap != null) {
  31. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
  32. }
  33. request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  34. request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  35.  
  36. try {
  37. doDispatch(request, response); //重点
  38. }
  39. finally {
  40. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  41. // Restore the original attribute snapshot, in case of an include.
  42. if (attributesSnapshot != null) {
  43. restoreAttributesAfterInclude(request, attributesSnapshot);
  44. }
  45. }
  46. }
  47. }

最后调用doDispatch(request, response)方法完成处理(后续代码有时间在跟踪)。

过程总结:

Servlet的生命周期以及在Spring MVC中调用流程的更多相关文章

  1. Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用

    Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/1019 ...

  2. Spring,SpringMVC,MyBatis,Hibernate,Servlet的生命周期,jsp有哪些内置对象,Tomcat,Cookie和Session的作用以及区别,oracle,MYSQL等面试题总结

    1. 什么是Spring,谈谈你对Spring的理解 Spring是我们JAVA开发人员在搭建后台时选用的一个轻量级的开源框架,Spring框架目前也是功能丰富,十分优秀企业级采用最多的一个框架. S ...

  3. Spring Bean的生命周期、Spring MVC的工作流程、IOC,AOP

    1.Spring Bean的生命周期? (1)构造方法实例化bean. (2)构造方法设置对象属性. (3)是否实现aware接口,三种接口(BeanNameAware,BeanFactoryAwar ...

  4. Servlet的生命周期及工作原理

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...

  5. Servlet的生命周期

    Servlet的生命周期 Servlet的生命周期是由tomcat服务器来控制的. 1 构造方法: 创建servlet对象的时候调用.默认情况下,第一访问servlet就会创建servlet对象只创建 ...

  6. Servlet的生命周期+实现方式

    1.Servlet的生命周期:        (1)被创建:            默认情况下,Servlet第一次被访问时,被服务器创建.会调用init()方法.                一个 ...

  7. Servlet基础(二) Servlet的生命周期

    Servlet基础(二) Servlet的生命周期 Servlet的生命周期可以分为三个阶段: 1.初始化阶段 2.响应客户请求阶段 3.终止阶段 Servlet的初始化阶段 在下列时刻Servlet ...

  8. JSP Servlet WEB生命周期

    [转载] JavaWeb的生命周期是由Servlet容器来控制的总的来说分为三个阶段1.启动阶段:加载web应用相关数据,创建ServletContext对象,对Filter和servlet进行初始化 ...

  9. servlet的生命周期与运行时的线程模型

    第 14 章 生命周期 注意 讲一下servlet的生命周期与运行时的线程模型,对了解servlet的运行原理有所帮助,这样才能避免一些有冲突的设计. 如果你不满足以下任一条件,请继续阅读,否则请跳过 ...

随机推荐

  1. Ajax之跨域请求

    一.引子 我现在开启了两个django项目,分别叫Demo1和Demo2,Demo1中有一个路径‘http://127.0.0.1:8000/index/’,对应的视图是index视图返回一个inde ...

  2. pip更新到18版本后使用pycharm更新问题:module 'pip' has no attribute 'main'

    今天升级pip到18.0版本后更新模块时出现错误 分析报错信息可知,问题出在packaging_tool.py文件的213行和109行,找到具体的代码,如下 # 109行函数 def do_insta ...

  3. anaconda更新库命令

    输入y更新库

  4. 通过swagger将API业务版本号与Gitlab代码版本号绑定

    1.调用Gitlab API获取项目commit ID 2.编辑 Swagger2.java @Configuration @EnableSwagger2 @EnableWebMvc public c ...

  5. Easyui-textbox得到焦点方法

    得到焦点是我们在编写前台时经常使用到的,为了提高用户的体验度,话不多说直接上代码. jsp页面: <div class="box_xian"> <span cla ...

  6. Linux常用基本命令:tr-替换或者删除字符

    tr命令 作用:从标准输入中替换,缩减或者删除字符,并将结果输出到标准输出 格式:tr [option] [set1] [set2] tr [选项] [字符1] [字符2] 把y替换m, o替换e,并 ...

  7. HDU5543(SummerTrainingDay03-O DP)

    Pick The Sticks Time Limit: 15000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others ...

  8. JSON方式封装通信接口

    1.封装通信接口数据的方法 2. 案例:生成json 注意:json_encode() 只能接收utf-8数据 测试: <?php $arr = array( 'id'=>1, 'name ...

  9. userDefineFunc.js

    var scareMe = function(){ console.log("cynthia") scareMe = function(){ console.log("w ...

  10. 3038 3n+1问题

    3038 3n+1问题  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 白银 Silver 题解       题目描述 Description 3n+1问题是一个简单有趣而又没有 ...