接触了一小段时间的servlet,以下就总结一下关于servlet的两个方面的知识,一个是模板方法的应用。另外一个是servlet多线程产生的原因。

1. 模板方法设计模式

定义一个操作中的算法的骨架。而将步骤延迟到子类中。

模板方法使得子类能够不改变一个算法的结构就可以重定义算法的某些特定步骤。

2. Servlet中模板方法的应用

模板方法在servlet中的应用的类图

当client请求一个servlet的时候首先被调用的是service方法。Service方法就是定义骨架的方法,在service方法中会依据HTTP请求的类型(GET,POST还是其它)来调用详细的doGet和doPost等方法;即实际的处理委派给了doGet和doPost等方法。这些子类的方法来终于处理浏览器的请求。以下是HttpServlet对service方法的详细实现。

protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod(); 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);
}
}

3. servlet并非严格的依照模板方法来设计的

我们常说详细问题详细分析。在这里也是。servlet 讲模板方法的精髓应用到了,可是却没有全然依照模板方法设计。

3.1 子类能够重写service()方法

模板方法模式是通过把不变的行为搬移到超类。去除了子类中的反复代码。所以超类中的模板方法普通情况下是不会被重写的。模板方法同意子类又一次定义算法的某些     步骤。而不改变算法的结构。可是在servlet中的service方法中是能够被子类重写的。当子类重写了service方法之后就破坏掉了原本定义好的模板方法。

3.2 doGet和doPost方法有默认的实现

在HttpServlet类中对于这两个被子类详细实现的方式是有实现的。

以下是HttpServlet对于这两个实现的代码

 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
    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);
}
}

这些说明在使用设计模式的时候并非生搬硬套,而是依据详细的情况灵活变动。可是其本质是不变的。

4.  为什么会出现线程安全问题

在学习servlet过程中一直听到的一个问题就是线程问题。学习的资料中提到servlet是多线程。不安全的。

servlet是由web容器管理的,当请求这个servlet的时候。web容器会依据web.xml中的配置实例化这个servlet。

当再次请求这个servlet的时候不会再实例化此servlet而是多线程的使用第一次请求的时候实例化的servlet。也就是一个servlet仅仅实例化一次。

当面对多个请求的时候web容器就会使用多线程来处理这些请求。

以下的图形是servlet多线程的结构图形

从图中能够看出,当容器收到一个请求servlet的请求的时候会从线程池中分出一个工作线程来处理这个请求,当有另外一个请求的时候会从线程池中分出另外一个工作线程来处理这个请求。所以假设多个用户同一时候请求同一个servlet,那么在容器中就会出现一个servlet对象的service方法并发运行。多线程是共享资源的,当他们并发运行的时候就非常有可能出现訪问资源冲突问题。

这样的处理请求的方式就是我们常常说的单实例多线程的处理方式。

以下是自己查找到的一个作者:http://blog.csdn.net/zljjava/article/details/6887266从内存的角度来分析的servlet的多线程问题。

假设有兴趣的话能够看看。

从内存中看一下这个问题能够总结以下的两种图形。当中一张是我们都知道JMM模型图

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveV9sb3ZlX2Y=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

另外一张是多个用户请求同一个servlet的多线程运行的过程是:

主内存中的实例变量是在多个线程之间共享的。每一个线程在自己的工作线程中拷贝自己须要的实例变量到自己的缓存中。就如同上面图形中的A,当线程1改动了A,可是线程2中的A还是主存中的样子,并没有立即同步到线程2和线程3中就会出现线程安全问题。

5. 总结

对于servlet的单实例多线程问题知道的原因就能够对症下药的找解决方式了。

主要是针对变量要注意。对于模板方法能够看到我们的应用非常多可是也要注意活学活用。

servlet之模板方法和多线程的更多相关文章

  1. Spring MVC:DispatchServlet类

    Spring MVC架构 Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中.传统的模型层被拆分为了业务层(Service)和数据访问层 ...

  2. Servlet 单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  3. Servlet单实例多线程模式

    http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以 ...

  4. servlet单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  5. 对于多线程下Servlet以及Session的一些理解

    今天,小伙伴突然问到了Servlet是不是线程安全的问题.脑子当时一卡壳,只想到了单实例多线程.这里做一些总结. Servlet体系是建立在Java多线程的基础之上的,它的生命周期是由Tomcat来维 ...

  6. Servlet 单例多线程【转】

    源地址:Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Ser ...

  7. [转]Servlet 单例多线程

    Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...

  8. Servlet 单例多线程详解(六)

    一.Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Servl ...

  9. Http协议&Servlet

    http协议 针对网络上的客户端 与 服务器端在执行http请求的时候,遵守的一种规范. 其实就是规定了客户端在访问服务器端的时候,要带上哪些东西, 服务器端返回数据的时候,也要带上什么东西. 版本 ...

随机推荐

  1. sqlserver远程备份到其他服务器

    直接将数据库备份到其他机器上 --如果xp_cmdshell没有启用,请先启用 sp_configure reconfigure go sp_configure reconfigure go --1. ...

  2. 【构建Android缓存模块】(一)吐槽与原理分析

    http://my.oschina.net/ryanhoo/blog/93285 摘要:在我翻译的Google官方系列教程中,Bitmap系列由浅入深地介绍了如何正确的解码Bitmap,异步线程操作以 ...

  3. JS回调函数全解析教程(callback)

    自学jQuery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速google之,发现原来中文翻译成回调.也就是回调函数了.不懂啊,于是在google回调函数,发现网上的中文解释实在是 ...

  4. Linux管道符

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFpanVucGVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  5. java 状态对象

    package cn.itcast.hibernate.sh.state; import org.hibernate.Session; import org.hibernate.Transaction ...

  6. jboss 的debug启动4法

    http://xo-tobacoo.iteye.com/blog/684946方式一: 使用myeclipse,全自动化,不再赘述 方式二: eclipse下使用server工具,部署后使用debug ...

  7. 一个表中的字段值用作另一个表的In查询条件

    Question表与Paper表 Paper表中字段QuestionIds存储的是Question表中字段Id的拼接后的值 如: 'f855eba1-b308-4bd7-a250-c071a0e1bd ...

  8. intellij中常用的快捷键

    intellij快捷键

  9. Laravel框架学习(Response)

    1.Response篇 1.1 基本响应 最基本的HTTP响应只需在路由闭包或控制器动作中返回一个简单字符串即可,但是具体业务逻辑中大部分响应都是在控制器动作中返回Response实例或者视图.Res ...

  10. Mono源码学习笔记:Console类(三)

    Buffer 类 (public static class) 以下就是 mcs/class/corlib/System/Buffer.cs: 001: // 002: // System.Buffer ...