servlet生命周期的各个阶段:
1.加载和实例化
根据Servlet请求的路径,查找该Servlet的实例。如果实例不存在,则通过调用构造方法,完成Servlet实例的创建。
2.初始化
调用Servlet对象的init()方法,初始化Servlet的信息,init()方法只会在创建后被调用一次(初始化阶段)。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,创建于用户第一次调用该 Servlet 的 URL 时,也可以指定 Servlet 在服务器第一次启动时被加载。当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
3.服务
通过该Servlet的实例,调用service()方法,如果子类没有重写该方法,则调用HttpServlet父类的service()方法,在父类的该方法中进行请求方式的判断,如果是GET
请求,则调用doGet()方法;如果是POST
请求,则调用doPost()方法;响应请求,调用service()或者是doGet(),doPost()方法来处理请求,这些方法是运行的在多线程状态下的,(响应客户请求阶段)。service() 方法是执行实际任务的主要方法,处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。Servlet接收和响应客户请求的过程,首先客户发送一个请求,Servlet是调用service()方法对请求进行响应的,通过源代码可见,service()方法中对请求的方式进行了匹配,选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。由于在Servlet接口和GenericServlet中是没doGet,doPost等等这些方法的,HttpServlet中定义了这些方法,所以,我们每次定义一个Servlet的时候,都必须实现doGet或 doPost等这些方法。
4.销毁
服务器关闭或重启时,会销毁所有的servlet实例,调用Servlet实例的destory()方法。destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
Servlet不是线程安全的,servlet是单实例多线程的,当多个线程同时访问同一个方法,是不能保证共享变量的线程安全性的。
因为servlet是多线程的,而servlet的生命周期由容器进行管理(Tomcat)。当客服端对servlet第一次进行请求时候,服务器(tomcat)会实例化这个serlvet。当用户再对该serlvet进行请求时候,不会再对该serlvet进行实例了。这里都是共享一个servlet对象(为单例模式)。这样会导致出现的状况是,多个线程进行请求同一个serlvet时候,只要对serlvet的实例变量进行操作时候,这时候会导致了该实例变量时候,会出现数据不一致的状况。这样会导致一系列的安全问题。