Servlet生命周期

Servlet生命周期

简介:理解一个对象在程序中的存活时间,有利于提高代码质量。也是剖析每个程序运行原理的关键。

 

一、对象的生命周期

1. 创建阶段(Created) 

被实例化(new)调用构造器时

· Jvm为对象分配存储空间

· 开始构造对象

· 从父类到子类对static成员进行初始化

· 父类成员变量按照顺序初始化,递归调用父类的构造方法

· 子类成员变量按照顺序初始化,子类构造方法调用一旦对象被创建,并有某个引用指向它,这个对象的状态就切换到了应用阶段(In Use)

2.应用阶段(In Use)

对象至少被一个强引用持有并且对象在作用域内

3. 不可见阶段(Invisible)

程序本身不再持有该对象的任何强引用,但是这些引用可能还存在着;一般具体是指程序的执行已经超过该对象的作用域了

4. 不可达阶段(Unreachable)

该对象不再被任何强引用所持有;可能仍被JVM等系统下的某些已经装载的惊天变灵或者线程或JNI所持有,这些特殊的强引用被称为GC root,这种情况容易导致内存泄露,无法被回收

5. 收集阶段(Collected)

对象不可达,并且GC已经准备好对该对象占用的内存空间重新分配的时候,处于收集阶段。如果重写了finazlie()方法,则会去执行该方法。

尽量不要重写finazlie()方法,因为有可能影响JVM的对象分配与回收速度或者可能造成该对象的再次复活

6. 终结阶段

当对象执行完finalize()方法之后,仍然处于不可达状态时,则该对象进入终结阶段。在这个阶段,内存空间等待GC进行回收

7. 对象空间的重新分配

GC对该对象占有的内存空间进行回收或者再分配,该对象彻底消失(jvm的垃圾回收机制

 

 

 

二、Servlet的生命周期

 

Servlet运行原理 

 

 

Servlet生命周期定义了一个Servlet如何被加载、初始化,以及它怎样接收请求、响应请求,提供服务。在讨论Servlet生命周期之前,先让我们来看一下这几个方法:

1. init()方法

      Servlet的生命周期中,仅执行一次init()方法,它是在服务器装入Servlet时执行的,可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()

2. service()方法 (重点)

      它是Servlet的核心,每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个请求ServletRequest)对象和一个响应ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。(也就说是所有请求的入口)

注意:服务器是默认调用service()方法的然后会根据条件,再调用对对应的do方法

如果重写service()方法则do等功能方法失效。不建议重写

3. destroy()方法

      仅执行一次,在服务器端停止且卸载Servlet时执行该方法,有点类似于C++delete方法。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

 

其实Servlet的生命周期就是对象的生命周期,只不过有些阶段是容器决定的

主要可以总结为为三个阶段:

1,初始化阶段 调用init()方法

2,响应客户请求阶段  调用service()方法

3,终止阶段  调用destroy()方法

 

   Servlet的生命周期是由Servlet容器来控制的,它始于装入Web服务器的内存时,并在终止或重新装入Servlet时结束。这项操作一般是动态执行的。然而,Server通常会提供一个管理的选项,用于在Server启动时强制装载和初始化特定的Servlet

     在代码中,Servlet生命周期由接口javax.servlet.Servlet定义。所有的Java Servlet必须直接或间接地实现javax.servlet.Servlet接口,这样才能在Servlet Engine上运行。javax.servlet.Servlet接口定义了一些方法,在Servlet的生命周期中,这些方法会在特定时间按照一定的顺序被调用。

 

Servlet生命周期

加载和实例化Servlet

我们来看一下Tomcat是如何加载的:

     1. 如果已配置自动装入选项,则在启动时自动载入。

     2. 在服务器启动时,客户机首次向Servlet发出请求。

     3. 重新装入Servlet时。(反射)

      当启动Servlet容器时,容器首先查找一个配置文件web.xml,这个文件中记录了可以提供服务的Servlet。每个Servlet被指定一个Servlet名,也就是这个Servlet实际对应的Java的完整class文件名。Servlet容器会为每个自动装入选项的Servlet创建一个实例。所以,每个Servlet类必须有一个公共的无参数的构造器。

初始化

      Servlet被实例化后,Servlet容器将调用每个Servletinit方法来实例化每个实例,执行完init方法之后,Servlet处于已初始化状态。所以说,一旦Servlet被实例化,那么必将调用init方法。通过Servlet在启动后不立即初始化,而是收到请求后进行。在web.xml文件中用<load-on-statup> ...... </load-on-statup>Servlet进行预先初始化。

      初始化失败后,执行init()方法抛出ServletException异常,Servlet对象将会被垃圾回收器回收,当客户端第一次访问服务器时加载Servlet实现类,创建对象并执行初始化方法。

init()方法只被调用一次。

请求处理

      Servlet 被初始化以后,就处于能响应请求的就绪状态。每个对Servlet的请求由一个Servlet Request对象代表。Servlet给客户端的响应由一个Servlet Response对象代表。对于到达客户机的请求,服务器创建特定于请求的一个请求对象和一个响应对象。调用service方法,这个方法可以调用其他方法来处理请求。

      Service方法会在服务器被访问时调用,Servlet对象的生命周期中service方法可能被多次调用,由于web-server启动后,服务器中公开的部分资源将处于网络中,当网络中的不同主机(客户端)并发访问服务器中的同一资源,服务器将开设多个线程处理不同的请求,多线程同时处理同一对象时,有可能出现数据并发访问的错误。

      另外注意,多线程难免同时处理同一变量时(如:对同一文件进行写操作),且有读写操作时,必须考虑是否加上同步,同步添加时,不要添加范围过大,有可能使程序变为纯粹的单线程,大大削弱了系统性能;只需要做到多个线程安全的访问相同的对象就可以了。

终止阶段/卸载Servlet    

destroy()方法

 

      当服务器不再需要Servlet实例或重新装入时,会调用destroy方法,使用这个方法,Servlet可以释放掉所有在init方法申请的资源。一个Servlet实例一旦终止,就不允许再次被调用,只能等待被卸载。

      Servlet一旦终止,Servlet实例即可被垃圾回收,处于卸载状态,如果Servlet容器被关闭,Servlet也会被卸载,一个Servlet实例只能初始化一次,但可以创建多个相同的Servlet实例。如相同的Servlet可以在根据不同的配置参数连接不同的数据库时创建多个实例。

 

 

 

Java实例

 

import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ServletLifeCycle extends HttpServlet {
 
private static final long serialVersionUID = 1L;
 
 
/**
 *  在Servlet的生命周期中,仅执行一次init()方法,
 *  它是在服务器装入Servlet时执行的,可以配置服务器,
 *  以在启动服务器或客户机首次访问Servlet时装入Servlet。
 *  无论有多少客户机访问Servlet,都不会重复执行init();
 *  所以可以用来初始化一些参数
 */
public void init() throws ServletException {
System.out.println("init() 用来初始化一些参数");
}
 
/**
 * 服务器是默认调用service()方法的然后会根据条件,
 * 再调用对对应的do方法如果重写service()方法则do等功能方法失效。
 * 不建议重写
 */
@Override
public void service(HttpServletRequest req, HttpServletResponse resp){
System.out.println("service()   重写之后不掉用其他doGet方法");
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("如果重写service()  则不会被调用");
}
 
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
 
/**
 *  仅执行一次,在服务器端停止且卸载Servlet时执行该方法,有点类似于C++的delete方法。
 *  属于垃圾回收机制
 */
public void destroy() {
System.out.println("destroy在服务器段停止且卸载servlet是执行该方法");
}
}
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值