Servlet的生命周期

Servlet的生命周期

servlet的生命周期就是从servlet出现到销毁的全过程。主要分为以下几个阶段:
加载类—>实例化(为对象分配空间)—>初始化(为对象的属性赋值)—>请求处理(服务阶段)—>销毁

服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf),该servlet对象去处理所有客户端请求,service(ServletRequest req,ServletResponse res)方法中执行,最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。其中加载阶段无法观察,但是初始化、服务、销毁阶段是可以观察到的。

在这里插入图片描述

public class EmpServlet extends HttpServlet{
	//初始化servlet,调用init方法
	@Override
	public void init() throws ServletException {
		System.out.println("初始化时调用");
	}
	//开启服务
	@Override
	protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		System.out.println("开启服务时调用");
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}
	//销毁时调用destory
	@Override
	public void destroy() {
		System.out.println("销毁时调用");
	}
}

在这里插入图片描述
思考问题
为什么创建的servlet是继承自httpServlet,而不是直接实现Servlet接口?

解答:
首先我们来看下源码,HttpServlet的继承结构
在这里插入图片描述
HttpServlet继承了GenericServlet,GenericServlet是一个通用的Servlet,那么他的作用是什么呢?大概的就是将实现Servlet接口的方法,简化编写servlet的步骤。
GenericServlet的继承结构:
在这里插入图片描述
实现了Servlet接口和ServletConfig接口

Servlet接口的内容

public interface Servlet {
	void init(ServletConfig var1) throws ServletException;

	ServletConfig getServletConfig();

	void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

	String getServletInfo();

	void destroy();
}

从这里可以看到,Servlet生命周期的三个关键方法,init、service、destroy。还有另外两个方法,一个getServletConfig()方法来获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息,ServletName、ServletContext、InitParameter、InitParameterNames、通过查看ServletConfig这个接口就可以知道

public interface ServletConfig {
	String getServletName();

	ServletContext getServletContext();

	String getInitParameter(String var1);

	Enumeration<String> getInitParameterNames();
}

其中ServletContext对象是servlet上下文对象,功能有很多,获得了ServletContext对象,就能获取大部分我们需要的信息,比如获取servlet的路径,等方法。

到此,就知道了Servlet接口中的内容和作用,总结起来就是,三个生命周期运行的方法,获取ServletConfig,而通过ServletConfig又可以获取到ServletContext。而GenericServlet实现了Servlet接口后,也就说明我们可以直接继承GenericServlet,就可以使用上面我们所介绍Servlet接口中的那几个方法了,能拿到ServletConfig,也可以拿到ServletContext,不过那样太麻烦,不能直接获取ServletContext,所以GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,那样,就可以直接获取ServletContext了。

在这里插入图片描述
上图我们观察到,init方法存在两个,一个带参,一个无参

private transient ServletConfig config;
public void init(ServletConfig config) throws ServletException {
		this.config = config;
		this.init();
	}

	public void init() throws ServletException {
	}
	public ServletConfig getServletConfig() {
		return this.config;
	}

通过这几个方法一起来讲解,首先看init(ServletConfig config)方法,因为只有init(ServletConfig config)中带有ServletConfig对象,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,然后通过getServletConfig()方法就能够获取ServletConfig对象了,这个可以理解,但是在init(ServletConfig config)中,158行,还调用了一个init()方法,并且这个init()方法是空的,什么读没有,这是为什么呢?这个原因是为了防止一件事情,当我们需要在init方法中做一点别的事情,我们想到的方法就是继承GenericServlet并且重写了init(ServletConfig config)方法,这样依赖,就破坏了原本在GenericServlet类中init(ServletConfig config)写的代码了,也就是在GenericServlet类中的成员变量config会一直是null,无法得到赋值,因为被重写了,就不会在执行GenericServlet中init(ServletConfig config)方法中的代码。要想赋值,就必须在重写的init(ServletConfig config)方法中调用父类的init(ServletConfig config)方法,也就是super.init(ServletConfig config),这样一来,就很不方便,怕有时候会忘了写这句代码,所以在GenericServlet类中增加一个init()方法,以后需要在init方法中需要初始化别的数据,只需要重写init()这个方法,而不需要去覆盖init(ServletConfig config)这个方法,这样设计,就好很多,不用在管init(ServletConfig config)这个其中的内容了。也不用出现其他的问题。

总结:
Servlet的生命周期分为:加载阶段、实例化阶段、初始化阶段、服务阶段、销毁阶段。上面我们说了servlet默认是第一次被访问的时候初始化的,这种情况当用户要使用的时候才创建,也可以在服务器一启动的时候就创建好servlet(这种方式一般不用),要实现这样的操作需要进行配置,在web.xml中进行配置
在这里插入图片描述

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页