Servlet是什么?

    Servlet是运行于服务器端,使用Java Servlet API 以及相关类和方法实现的Java程序。

为什么说Servlet独立于平台?

    Java Servlet API 定义了一个 Servlet和Java使能服务器(Servlet 容器)之间的一个标准接口,这使得Servlet具有跨平台的特性。

为什么说Servlet与协议无关?

    Servlet不对具体的协议实现,可以接受自定义协议,常用的WEB项目HttpServlet 是对HTTP协议的实现,我们可以像HttpServlet一样扩展GenericServlet 来实现FtpServlet,TelnetServlet等等。

为什么说Servlet相对高效?

    Servlet在第一次被请求加载时调用init方法初始化一个Servlet,当后续的客户请求 servlet 服务时,Web 服务都将启动一个新的线程,而不是启动一个进程,这些线程由Servlet引擎服务器来管理,与传统的 CGI 为每个客户启动一个进程相比较,效率要高的多。

Servlet的生命周期

    Servlet 的生命周期始于将它装入 Web 服务器的内存时,并在终止或重新装入 Servlet 时结束。Servlet的生命周期大致分三个阶段:

1. 初始化。

    装入 Servlet 后,服务器创建一个 Servlet 实例并且调用 Servlet 的 init() 方法。在初始化阶段,Servlet 初始化参数(ServletConfig)传递给 Servlet 配置对象。 初始化的三个时机:

    1.1 如果已配置自动装入选项,则在启动服务器时自动装入。

    1.2 在服务器启动后,客户机首次向 Servlet 发出请求时。

    1.3 重新装入Servlet时。

2. 请求处理

    对于到达服务器的客户机请求,服务器创建特定于请求的一个“请求”对象和一个“响应”对象。服务器调用 Servlet 的 service() 方法,该方法用于传递“请求”和“响应”对象。service() 方法从“请求”对象获得请求信息、处理该请求并用“响应”对象的方法以将响应传回客户机。service() 方法可以调用其它方法来处理请求,例如 doGet()、doPost() 或其它的方法。 

    例如对于Http请求:

//HttpServlet中service方法
public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest        request;
        HttpServletResponse        response;
        
        try {
            request = (HttpServletRequest) req;//创建特定于请求的“请求”对象
            response = (HttpServletResponse) res;//创建特定于请求的“响应”对象
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);//看下方service()方法代码
 }

  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, 或重新装入 Servlet 的新实例时,服务器会调用 Servlet 的 destroy() 方法。 

Java Servlet API简介

    Java Servlet 开发工具(JSDK)提供了多个软件包,在编写 Servlet 时需要用到这些软件包。其中包括两个用于所有 Servlet 的基本软件包:javax.servlet 和 javax.servlet.http。javax.servlet包中的类都是抽象的,比较高层的,与协议无关的。下面主要介绍javax.servlet.http提供的HTTP Servlet应用编程接口。

    HTTP Servlet 使用一个 HTML 表格来发送和接收数据。要创建一个 HTTP Servlet,需扩展 HttpServlet 类, 该类是用专门的方法来处理 HTML 表格的 GenericServlet 的一个子类。 HttpServlet 类包含 init()、destroy()、service() 等方法。其中 init() 和 destroy() 方法是继承的。

    相关类图:

Java Sevlet 技术

    下面重点说几个常用且重要的方法:

1. init()方法

    在 Servlet 的生命期中,仅执行一次 init() 方法。它是在服务器装入 Servlet 时执行的。 可以配置服务器,以在启动服务器或客户机首次访问 Servlet 时装入 Servlet。 无论有多少客户机访问 Servlet,都不会重复执行 init() 。

2. service()方法

    service() 方法是 Servlet 的核心。每当一个客户请求一个HttpServlet 对象,该对象的service() 方法就要被调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。

3. destroy() 方法
  destroy() 方法仅执行一次,即在服务器停止且卸装Servlet 时执行该方法。典型的,将 Servlet 作为服务器进程的一部分来关闭。缺省的 destroy() 方法通常是符合要求的,但也可以覆盖它,典型的是管理服务器端资源。

Servlet线程安全性问题

    Servlet是非线程安全的。Servlet的线程安全问题主要是由于实例变量使用不当而引起。

    Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行。

    这样,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。

    线程安全问题主要是由实例变量造成的,因此:

    1. 在Servlet中应避免使用实例变量。

    2. 如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。

相关文章:

  • 2021-08-10
  • 2021-10-23
  • 2022-02-07
  • 2022-02-07
  • 2021-08-17
  • 2022-02-26
  • 2022-12-23
猜你喜欢
  • 2021-12-08
  • 2021-05-13
  • 2022-01-31
  • 2021-04-09
  • 2021-09-07
  • 2021-11-11
  • 2022-01-10
相关资源
相似解决方案