八岁到十八岁,这中间有十年,十八岁到二十八岁这中间却是很多人的一生,人的一生从呱呱坠地到化作一捧黄土。或波澜壮阔到在历史书上一页都写不下,或碌碌无为淹没在人海中。人是如此,那么Servlet呢?它的一生又是什么样的呢?今天我们就来聊聊这个问题。
了解Servelet的一生之前,我想我们首先应该搞清楚,什么是生命周期,很多人可能会说,这个词汇我曾见过的,没错,生命周期这个词汇在我们学习java单线程多线程的时候就见过的,一个线程从创建到消亡,便是线程的一生,那么Servlet呢?亦是如此。
Servlet的生命周期可以分为四个阶段:实例化阶段、初始化阶段、服务阶段、销毁阶段。下面我们围绕着四个阶段展开分析。
一、实例化阶段:
接下来我们直接启动服务器,来测试,首先我们访问一下Test2。
出现404界面。因为这个注解类名不存在,说明不是随随便便就能制造出来Servlet的实例的,而是要根据我们注解中的类名来实例化我们的Servlet,页面访问输出正常,控制台打印正常。
接下来我们创建一个Test2测试的Servlet,除了打印语句和注解类名不变之外,其余所有参数保持一致。
接下来我们重启服务器直接访问Test1.do来观察控制台打印数据情况,看看是打印Test1.do的无参构造语句还是打印Test1.do+Test2.do两个的无参构造语句。
测试结果为单纯打印Test1.do的输出语句,我又重启服务器测试了一下Test2.do,结果也是单纯的只打印Test2.do的输出语句,由此我们得出结论,默认状态下只有当我们在使用或者访问对应的Servlet时才会进行对象的创建,如果不使用或者不访问,则一直处于无实例状态。
二、初始化阶段:
Servlet实例化后就会调用init方法,并且只能调用一次,且是在进行第一次实例化Servlet对象时调用。当用户在访问Servlet时,就会创建一个对应的Servlet实例,每一次在客户端发送一个请求,Servlet就会产生一个新的线程,从而调用对应的doGet 或 doPost 方法。init方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。接下来我们通过一个测试案例来看一下这个方法。
我们直接访问对应的Servlet会发现,已经自动调用了init方法,也就是说,实例化结束后Servlet会自己调用这个方法来加载一些数据。
三、服务阶段:
Service方法是执行实际任务的主要方法,Web服务器将调用Service方法处理客户端(浏览器)的请求,然后将处理完乱码的数据响应给浏览器客户端。每当客户端向服务端发送一个请求时,服务端都会产生一个新的线程调用服务。Service方法将会检测客户端发送给服务端的HTTP请求协议的类型,从而调用Service方法中的 doGet、doPost 等方法进行实际任务的逻辑处理。这里我给Test3.do的Servlet加一个Service方法,我直接来通过这段代码来测试一下。
实例化完成后调用init方法,因为我的本次访问相当于也是一个请求,所以Servlet也会自动调用Service方法打印一次。
此时,Servlet已经成功实例化,并且已经调用过一次init方法,后续我们只需要刷新当前页面,就会一直单纯的调用Service方法,处理我们的请求,也就是打印我们的输出语句到控制台,不停的为我们提供服务。
四、销毁阶段:
Servlet生命周期结束时将会调用destroy()方法,并且只会调用一次。destroy方法可以让我们的Servlet关闭数据库连接,把后台线程关闭,清楚Cookie数据等。当调用了destroy()方法后,当前Servlet实例将会被标记为回收垃圾,会对Servlet实例进行清除,这里我们通过一个测试案例来分析。
自动调用init和Service方法执行后我们停止掉Tomcat服务器,注意是停止不是关闭,然后就会发现Servlet已经被销毁了。
实例化:Servlet容器创建Servlet对象。默认创建Servlet实例的时机:当我们发送Servlet对应的请求时(在使用时创建)。容器只会让Servlet实例化一次,类似单例模式中的懒加载方式。如果希望容器一旦启动,就自动创建Servlet实例通过设置优先级,优先实例化。
初始化:Servlet实例一旦创建,就开始初始化一些参数配置,我们可以做一些参数配置,比如处理乱码等等,可以在web.xml或注解中配置。
服务阶段:当发送对应的Servlet请求时,会调用Service()方法,注意此时不会重新创建Servlet实例,也不会调用init()方法。
销毁阶段:调用了destroy()方法后,当前Servlet实例将会被标记为回收垃圾,会对Servlet实例进行清除处理。传