JavaWeb Servlet概要

一、Servlet简介

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是做为来自 Web 浏览器或其余 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,能够收集来自网页表单的用户输入,呈现来自数据库或者其余源的记录,还能够动态建立网页。
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),须要完成如下2个步骤:
  一、编写一个Java类,实现servlet接口。
  二、把开发好的Java类部署到web服务器中。
  按照一种约定俗成的称呼习惯,一般咱们也把实现了servlet接口的java程序,称之为Servlet。html

二、Servlet调用机制

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
  ①Web服务器首先检查是否已经装载并建立了该Servlet的实例对象。若是是,则直接执行第④步,不然,执行第②步。
  ②装载并建立该Servlet的一个实例对象。
  ③调用Servlet实例对象的init()方法。
  ④建立一个用于封装HTTP请求消息的HttpServletRequest对象和一个表明HTTP响应消息的HttpServletResponse对象,而后调用Servlet的service()方法并将请求和响应对象做为参数传递进去。
  ⑤WEB应用程序被中止或从新启动以前,Servlet引擎将卸载Servlet,并在卸载以前调用Servlet的destroy()方法。java

三、Servlet 生命周期

Servlet 生命周期可被定义为从建立直到毁灭的整个过程。如下是 Servlet 遵循的过程:web

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

四、Servlet 任务

Servlet 执行如下主要任务:数据库

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也能够是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能须要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式能够是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其余客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其余相似的任务。

五、Servlet实例

@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet", "/myServlet"})
public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("----------doPost-----------");
        doGet(request, response);
}

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("----------doGet-----------");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.print("    This is ");
        out.print(this.getClass());
        out.println(", using the GET method");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

六、Servlet注册方式

6.一、web.xml方式(传统方式)

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>org.silence.servlet.MyServlet</servlet-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>zhangsan</param-value>
    </init-param>
    <display-name>MyServlet</display-name>
</servlet>
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/servlet</url-pattern>
</servlet-mapping>

6.二、@WebServlet注解方式(servlet3.0开始)

注意:Servlet3.0的项目服务器须要Tomcat7.0开始的版本才支持!!浏览器

@WebServlet(name = "ParamServlet",
        urlPatterns = "/param",
        initParams = {@WebInitParam(name = "name", value = "zhangsan"), @WebInitParam(name = "abc", value = "abc")})
public class ParamServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        ServletConfig config = getServletConfig();
        String name = config.getInitParameter("name");
        response.getWriter().println(name);

        Enumeration<String> parameterNames = config.getInitParameterNames();
        while (parameterNames.hasMoreElements()) {
            String element = parameterNames.nextElement();
            String parameter = config.getInitParameter(element);
            response.getWriter().println(element + " = " + parameter);
        }
    }
}

七、Servlet线程安全

在默认的状况下Servlet容器(web服务器)对声明的Servlet,只建立一个Servlet实例,当多个客户端并发访问同一个Servlet时,Servlet容器会为每个客户端的访问请求建立一个线程,并在这个线程上调用Servlet的service方法,所以service方法内若是访问了同一个资源的话,就有可能引起线程安全问题。

例以下面的代码:缓存

@WebServlet(name = "SynServlet", urlPatterns = "/syn")
public class SynServlet extends HttpServlet {
    int i = 1;

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        synchronized (this) {
        i++;
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        response.getWriter().write("i: " + i);
//        }
    }
}

解决办法之一是给共享资源加锁。安全

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    synchronized (this) {
        i++;
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        response.getWriter().write("i: " + i);
    }
}

7.一、Servlet线程安全的解决方式

7.1.一、实现javax.servlet.SingleThreadModel接口(不推介)

javax.servlet.SingleThreadModel API及其翻译服务器

  Ensures that servlets handle only one request at a time. This interface has no methods.cookie

  确保servlet每次只处理一项请求。接口不含方法。session

  If a servlet implements this interface, you are guaranteed that no two threads will execute concurrently in the servlet's service method. The servlet container can make this guarantee by synchronizing access to a single instance of the servlet, or by maintaining a pool of servlet instances and dispatching each new request to a free servlet.

  *若是servlet实现了该接口,会确保不会有两个线程同时执行servlet的service方法。 servlet容器经过同步化访问servlet的单实例来保证,也能够经过维持servlet的实例池,对于新的请求会分配给一个空闲的servlet。*

  Note that SingleThreadModel does not solve all thread safety issues. For example, session attributes and static variables can still be accessed by multiple requests on multiple threads at the same time, even when SingleThreadModel servlets are used. It is recommended that a developer take other means to resolve those issues instead of implementing this interface, such as avoiding the usage of an instance variable or synchronizing the block of the code accessing those resources. This interface is deprecated in Servlet API version 2.4.

  *注意:SingleThreadModel不会解决全部的线程安全隐患。*例如,会话属性和静态变量仍然能够被多线程的多请求同时访问,即使使用了SingleThreadModel servlet。

7.1.二、同步共享资源(推介)

使用synchronized或提供的锁来同步共享资源。

7.1.三、避免使用实例变量
相关文章
相关标签/搜索