目录
一、Servlet生命周期
servlet的生命周期是初始化,服务,销毁。
初始化:
当第一次请求servlet的时候进行初始化,只初始化一次;
服务:
方法被调用时进行服务,在项目启动期间可以进行多次服务;
销毁:
当服务器关闭时进行销毁,只销毁一次;
二、Servlet的初始化阶段
当需要Servlet来处理请求时,web容器会检查缓存中是否存在对应的Servlet,如果没有就创建,如果缓存中存在了,那么就直接拿来使用。所以说,Servlet是在接收到第一个处理请求时被创建的,也可以通过配置load-on-startup的值为1设置Servlet随服务器启动就创建对象。(特殊业务需求才使用程序启动自动创建Servlet对象,否则会增加服务器的启动时间,消耗性能)
当web容器创建Servlet成功后,会且只会调用一次init()方法,在后续每次需要这个Servlet处理请求时不再调用,可以利用init对Servlet进行初始化操作,web容器在创建Servlet对象时,会创建ServletConfig对象(代表Servlet配置),并在调用init方法时,把该对象当作参数传递进来,通过该对象可以获取Servlet的信息,所以调用init方法时可以通过ServletConfig获取Servlet的信息。每次服务器接收到一个Servlet请求时,服务器会产生一个新的线程,根据http请求类型,调用对应的doGet、doPost方法进行处理;
三、Servlet的服务阶段
Service方法是执行实际任务的主要方法,Web服务器将调用Service方法处理客户端(浏览器)的请求,然后将处理完乱码的数据响应给浏览器客户端。每当客户端向服务端发送一个请求时,服务端都会产生一个新的线程调用服务。Service方法将会检测客户端发送给服务端的HTTP请求协议的类型,从而调用Service方法中的 doGet、doPost 等方法进行实际任务的逻辑处理。这里我给Test3.do的Servlet加一个Service方法,我们通过下面的代码来测试一下。
实例化完成后调用init方法,因为我的本次访问相当于也是一个请求,所以Servlet也会自动调用Service方法打印一次。
此时,Servlet已经成功实例化,并且已经调用过一次init方法,后续我们只需要刷新当前页面,就会一直单纯的调用Service方法,处理我们的请求,也就是打印我们的输出语句到控制台,不停实现服务功能。
四、Servlet的销毁阶段
当web服务器被关闭时,会把Servlet进行销毁。在Servlet生命周期结束时会且只会调用一次destroy()方法把Servlet销毁,关闭数据库连接,停止后台线程,释放资源等。我们可以重写destroy()方法处理被销毁之前的业务。在调用destroy方法后,Servlet对象会被标记为垃圾回收,等待jvm虚拟机回收。
五、Servlet的线程安全问题
线程安全 就是多线程在运行期间不会产生不符合常规的数据。同样在多线程访问同一代码,不会产生不确定的结果,线程安全首先呢他的是多线程,至少是2个。因为一个线程那肯定是线程安全的。就你自己一个线程执行没有人给你争用资源。你是在串行执行,不会出现不确定结果。 如果有多个线程,那问题可就多了。
由上图可以看出,servlet 是单例模式的,项目启动后只会有一个servlet实例,servlet的构造方法只执行了一次!因为servlet默认是单例模式,如果提供成员变量,多个线程对成员变量进行操作,将发生并发问题,所以是线程不安全的。如果不提供成员变量,或者提供成员变量不使用,可以解决并发问题。也可以使用异步方式调用,因为web服务需要保证并发量,如果使用线程安全,那么就需要等待一个请求之后才能执行下一个请求,这无疑会让客户端等待很长时间,而且如果遇到死锁问题,则必须重启服务器才能解决问题。