servlet的生命周期是什么?
指从出生到死亡的过程,对应于Servlet中的三个方法 init(), service(), destroy() 。
servlet生命周期的过程
默认情况
- 在第一次接受请求时,Tomcat容器会先调用构造方法实例化servlet,调用init()方法初始化,然后调用service()方法开始服务。
- 从第二次接受请求开始,容器直接调用service()开始服务,不再实例化和初始化。
- 关闭tomcat容器时,所有的servlet实例都会调用destroy()方法被销毁。
测试
创建一个测试类,继承HttpServlet,创建无参构造函数并重写三个方法。
public class Demo01 extends HttpServlet {
public Demo01(){
System.out.println("正在实例化。。。");
}
@Override
public void init() throws ServletException {
System.out.println("正在初始化。。。");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("开始服务。。。");
}
@Override
public void destroy() {
super.destroy();
System.out.println("servlet已被销毁。。。");
}
}
在配置文件web.xml中写入
<servlet>
<servlet-name>Demo01Server01</servlet-name> <!--与第八行的名字保持一致-->
<servlet-class>com.servelt.Demo01</servlet-class> <!--类文件所在路径-->
</servlet>
<servlet-mapping>
<servlet-name>Demo01Server01</servlet-name> <!--可按自己的习惯取名-->
<url-pattern>/demo01</url-pattern> <!--servlet地址-->
<!--http://localhost:8080
</servlet-mapping>
运行后结果如下,当第一次打开网页时,实例化servlet,调用init(), service(), 重新进入网页后直接调用service()。关闭容器后显示servlet已被销毁。
结论
tomcat只会创建一个servlet实例并初始化,所有的请求都由这个实例响应,所以servlet是单例的,也因此servlet是线程不安全的,尽量不要在servlet中定义成员变量,如果不的不定义,也不要修改成员变量的值(设为常量)和根据变量的值做逻辑判断。默认情况下的时候,在第一次接收到请求的时候实例化和初始化对应的servlet。
优点
提高系统的启动速度
缺点
第一个发送请求的用户的等待时间较长,因为需要等待Tomcat容器实例化和初始化servlet。(可以通过配置<load-on-startup>来解决,见下)
自主设定实例化和初始化时机
通过在配置文件里配置<load-on-startup>整数</load-on-startup>来控制具体规则如下:
- 整数可以填正数、负数和0,当为大于等于0的整数时,表示在应用启动时容器就会实例化和初始化aervlet。
- 在这个整数大于等于0的情况下,数值越小优先级越高
- 当应用中有servlet时,可以通过配置不同整数数值来控制优先级
- 当为负数或未配置时,则默认在对这个servlet第一次发送请求时才实例化和初始化。
测试
<servlet>
<servlet-name>Demo01Server01</servlet-name> <!--与第八行的名字保持一致-->
<servlet-class>com.servelt.Demo01</servlet-class> <!--类文件所在路径-->
<load-on-startup>1</load-on-startup> <!--设置启动时实例化和初始化-->
</servlet>
<servlet-mapping>
<servlet-name>Demo01Server01</servlet-name> <!--可按自己的习惯取名-->
<url-pattern>/demo01</url-pattern>
</servlet-mapping>