基于上次的Servlet详解,描述了Servlet对象在应用中的生命周期,以及基本的XML文件配置,使得Tomcat容器去管理Servlet对象 .
在本块详解中,对Servlet类的继承体系进行详细描述.
这里呢我就用很简单的画一张继承体系图
GenericServlet是一个抽象类,可以处理普通的请求和响应,必须给出子类才可以进行实例化.它给出了设计Servlet的骨架和定义.提供了得到配置,初始化参数等方法.而HttpServlet则是它的实现子类,可以进行处理HTTP类型的请求和响应,在HttpServlet中添加了doGet,doPost,doDelete,doTrace等方法处理http协议中请求和响应.
只是一般我们都需要进行拓展HttpServlet所以需要进行重写.
package com._jerry._demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/demo")
//在Servlet3.0后,我们可以不再使用XML文件进行配置Servlet,而只有注解的形式进行解决,/demo是资源的路径,一般项目开发中我们省略资源的上下文路径,需要注意'/',资源前不能漏,否则会子启动Tomcat的时候即会报错.
public class DemoServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
public DemoServlet() {
System.out.println("调用构造器...");
// 提供一个构造器来演示方法调用的过程
}
public void init() throws ServletException {
System.out.println("初始化...");
/*这里需要注意的是在我们init方法其实是GenericServet方法暴露给HttpServet的方法:
//这段示例代码来自GenericServlet类
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
// NOOP by default
}
这种方法叫做钩子方法,原因在于父类中的init方法是用来获取配置参数的,而子偶自己的逻辑实现,所以提供一个init方法个给子类,然后在父类init方法中将子类的新增方法进行调用.
*/
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("service方法...");
}
public void destroy() {
// Servlet销毁的方法
System.out.println("销毁Servlet...");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
super.doGet(req, resp);
}
//---------------------------------------------------------
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
super.doPost(req, resp);
}
//这里的二个方法是HttpServlet类中定义的,本文就在自定义Servlet中重写了,主要是为了观察.在HttpServlet类中的Service方法其实会在请求中去获取当前的请求方式,然后再去调用对应的doGet方法或者doPost方法,取决于当前的请求是Get还是Post,但是因为我们自身开发的时候没有特殊需求下,一般会覆盖父类中的service方法所以也就不去关注doGet和doPost了.
//---------------------------------------------------------
}
为了看明白父类HttpServlet中service具体的代码,我们仔细看看
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
//其实以上也就是在做一个请求分发的操作,将对应的Get或者Post方法调用响应方法进行请求的处理.
Servlet类然后启动Tomcat服务器,在浏览器中访问已经配置好的这个Servlet资源,并进行测试
在控制台输出的结果为
调用构造器...
初始化...
service方法...
----------
再在浏览器中请求一次
显示如下:
调用构造器...
初始化...
service方法...
service方法...
从上面我们可以看出,在Tomcat启动后,我们在浏览器请求资源后,Tomcat先去管理Servlet,并且调用该Servlet的构造器进行实例化,然后和调用init方法进行参数初始化,最好调用service进行接收请求操作,再第二次的请求的时候,就只调service方法了,所以得知在每个Servlet对象的生命周期中,构造器和init方法只有在发起请求并访问该Servet资源的时候执行且只执行一次.
以上我们还可以注意到,Servlet中的destroy销毁方法并没有执行,其实这个一般是在Tomcat服务器关闭或者资源关闭的时候才会自己进行处理.