servlet的生命周期

servlet的特性

servlet的生命周期使得servlet能够处理CGI的性能和资源问题,以及低级别服务器API编程的安全性问题。servlet容器通常在一个JVM中执行多个servlet,能够高效方便地共享资源。同时由于Java语言的特性,能够避免相互访问私有数据。servlet能够像处理实例对象一样处理JVM中的请求,这种方法比使用完全的进程要节省很多内存,同时能够高效地访问外部资源。
servlet的生命周期非常灵活,servlet容器唯一需要严格遵守的规则是以下的生命周期约定:
1. 创建、初始化servlet;
2. 处理0个或多个客户端的服务请求;
3. 销毁servlet并进行垃圾回收。

只用一个Java虚拟机

实例的持续性

servlet像对象实例一样在请求之间保持持续性。也就是说,当servlet的代码被载入时,服务器生成一个实例,这个实例处理这个servlet的所有请求。它在三个方面提高了性能:
1. 内存消耗变少;
2. 节省生成一个servlet对象所需要的资源,当一个请求进入时,serlvet已经载入完毕,可以马上执行;
3. 保证持续性。一个servlet可能会把处理一个请求的所有可能用到的资源全部载入。例如,一个数据库连接可被打开一次而多次使用。这个连接甚至可以被多个servlet使用。(???
servlet不仅在请求之间保持连续性,对其生成的线程也是如此。可以令一个线程来计算,另一个线程进行结果的显示。

一个整体计数器

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HolisticCounter extends HttpServlet {

  static int classCount = 0;  // shared by all instances
  int count = 0;              // separate for each servlet
  static Hashtable instances = new Hashtable();  // also shared

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();

    count++;
    out.println("Since loading, this servlet instance has been accessed " +
                count + " times.");

    // Keep track of the instance count by putting a reference to this
    // instance in a hashtable. Duplicate entries are ignored.
    // The size() method returns the number of unique instances stored.
    instances.put(this, this);
    out.println("There are currently " +
                instances.size() + " instances.");

    classCount++;
    out.println("Across all instances, this servlet class has been " +
                "accessed " + classCount + " times.");
  }
}

用count变量统计HolisticCounter这个类的访问次数,用classCount统计共享的访问次数,用instance统计实例数量。(如何产生多个servlet?不是一个容器里面用一个servlet可以处理各种请求了吗?微服务是怎样的?

init和destroy

服务器在构造完servlet实例和处理任何请求之前运行servlet的init()方法,在servlet不用服务了或者所有挂起的请求处理完毕或超时时调用destroy()方法。
一个servlet的初始化参数在web.xml中,如

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
    <servlet>
        <servlet-name>
            counter
        </servlet-name>
        <servlet-class>
            InitCounter
        </servlet-class>
        <init-param>
            <param-name>
                initial
            </param-name>
            <param-value>
                1000
            </param-value>
            <description>
                The initial value for the counter  <!-- optional -->
            </description>
        </init-param>
    </servlet>
</web-app>

将多行的< init-param >放在< servlet >标签中。
在destroy()方法中,servlet应释放所有它占用的无法回收的所有存储单元,或者用于保存所有未保存的信息,或者为了保持持续性而要写入init()方法中以供下次初始化时读入的信息。

一个带初始化参数的计数器

public class InitCounter extends HttpServlet {

  int count;

  public void init() throws ServletException {
    String initial = getInitParameter("initial");
    try {
      count = Integer.parseInt(initial);
    }
    catch (NumberFormatException e) {
      count = 0;
    }
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res)
                           throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();
    count++;
    out.println("Since loading (and with a possible initialization");
    out.println("parameter figured in), this servlet has been accessed");
    out.println(count + " times.");
  }
}

带有init和destroy的计数器

保持载入之间的连续性–一个不会重新开始的计数器。
晕死。。。满心欢喜地看代码。。。。居然是在destroy()里面把参数写到文件里面,然后在init()里面读文件内容。。。。
如果服务器中途崩溃,那么destroy()方法不会被调用。

单线程模式

一般情况下,每个servlet注册名中只有一个servlet实例,但也有可能servlet为每个名字生成一组实例,这些实例共同处理请求(这个怎么操作?)。
这些servlet通过javax.servlet.SingelThreadModel接口实现,这个是一个空的“标签”,不定义任何方法或变量,只是服务器用来标志选择生命周期的servlet。
一个载入了SingleThreadModel servlet的服务器,必须保证servlet的service方法中没有同时执行的两个线程,所以必然是线程安全的。
单线程模型

注意,这样可能会让服务器产生过多的实例,应尽量避免使用。。。。。。
最好还是用线程池开多线程。

启动时载入

可以配置servlet的web.xml,使得服务器一开始就载入servlet(开始init()),通过< load-on-startup >标签实现。如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
    <servlet>
        <servlet-name>
            ps
        </servlet-name>
        <servlet-class>
            PrimeSearcher
        </servlet-class>
        <load-on-startup/>
    </servlet>
</web-app>

这个配置文件告诉服务器以注册名Ps创建一个primeSearch实例,并在服务器启动时用Init()初始化servlet。servlet能够被 URL/servlet/ps 所访问。注意,处理 URL/servlet/PrimeSearcher的servlet实例并没有在启动时被载入(没看懂?)。
这里< load-on-startup >标签是空的,如果带有数字,表示载入时的顺序,从小到大被载入。若为负数或非整数,可在启动的任何时刻被载入,取决于服务器规定的顺序。

客户端缓存

并不是所有请求都会调用doget()方法。只有在servlet输出改变时才向浏览器报告。这时调用的是getLastModified()方法。
大多数web服务器,它们会返回一个文档,其中包括响应的一部分:Last-Modified首部,例如:

Tue, 06-May-98 15:41:02 GMT

这个首部在它被浏览器下载时告诉服务器网页的Last-Modified时间,服务器根据这个判断给定时间文件是否有改动。如果有改动,服务器需要发送新的内容,否则,服务器告诉浏览器网页未变,可以重新显示缓存的内容。
这项技术对静态网页很有作用。

服务端缓存

为了实现服务端缓存,一个servlet必须:
1. 用扩展com.oreilly.servlet.CacheHttpServlet 代替 HttpServlet
2. 实现 getLastModified(HttpServletRequet)方法

关于客户端和服务端的缓存,可以参考这篇博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值