接触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中调用流程的更多相关文章

  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. Spark新手入门——1.Scala环境准备

    主要包括以下三部分,本文为第一部分: 一. Scala环境准备 二. Hadoop集群(伪分布模式)安装 查看 三. Spark集群(standalone模式)安装 查看 因Spark任务大多由Sca ...

  2. .10-浅析webpack源码之graceful-fs模块

    在cachedInput.output.watch三大文件系统中,output非常简单,没有必要讲,其余两个模块依赖于input模块,而input主要是引用了graceful-fs的部分API,所以这 ...

  3. git入门(廖雪峰老师)

    根据廖雪峰老师的git教程进行学习总结: 1.之前上班用的都是svn进行管理,那么svn和git有什么区别呢? svn是集中式的版本控制系统,而git是分布式版本控制系统,那么集中式和分布式版本控制系 ...

  4. Numbers、Strings、Lists 笔记<一>

    下一篇:流程控制<二> 阅读链接:官方Python3.7教程 废话:最近开始阅读python3.7文档,希望把容易混淆的知识记下来. 除法总是返回一个浮点数 >>> 8/ ...

  5. C# 单例模式和窗体的单例打开方法

    第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我…… public class Singleton{    private static Singleton ...

  6. 用CSS控制DIV居中失效的解决方法

    1.一般情况下DIV居中失效是因为没写DTD语句 在页面的最上方加上: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitiona ...

  7. canvas-star7.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Ubuntu 16.04 LTS 下安装 ibus-rime 输入法

    搜 Linux 下粤拼输入法的时候发现了 Rime,由于 fcitx 下的拼音输入体验实在不太好(搜狗是在我的电脑上完全坏掉了,调不出来,配置文件的问题一直没解决:谷歌是好过没有),于是安装 ibus ...

  9. Git应用--04遇到冲突解决办法git stash(转载)

    git merge git pull时候遇到冲突解决办法git stash https://www.cnblogs.com/juandx/p/5362723.html 在使用git pull代码时,经 ...

  10. openlayer3之高级标注实现

    首先看实现效果: 实现要点: 1)树形标注实现 2)复杂标注样式定义 3)效率优化 1.树形标注实现 树形标注采用字体符号来实现,包括以下几个步骤 1)载入字体 2)设置标注值与字体对照关系 3)设置 ...