在讲述Servlet的生命周期之前,我们一定要了解什么是Servlet?
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
在Web开发阶段,我们如果要编写一个完善的服务器,就要关注许多繁琐的格式化的基础语句,一个简单的html页面就可能需要上千行底层代码:
- //基于TCP协议连接+HTTP协议通信的服务器端
- public class HttpServer01 {
- public static void main(String[] args) {
- try (ServerSocket serverSocket = new ServerSocket(8080)) {
- while(true) {
- //客户端基于HTTP协议发起请求
- Socket socket= serverSocket.accept();
- System.out.println("有新的客户端连接");
- //读取到客户端的请求头内容(基于HTTP协议格式)
- try(BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
- BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
- String line=null;
- while((line=reader.readLine())!=null) {
- //读到空行,代表请求头结束
- //由于是GET请求,不存在request body(请求体)
- //所以退出请求头的读取
- if (line.length()==0) {
- break;
- }
- System.out.println(line);
- }
- System.out.println("开始响应...");
- String response="优惠券:"+UUID.randomUUID().toString()+"";
- // response header 响应头
- writer.write("HTTP/1.1 200 ok\r\n");
- writer.write("Connection:close\r\n");
- writer.write("Content-Type:text/html\r\n");
- ...
- writer.newLine();
- writer.newLine();
- writer.write(response);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
以上代码是一个简单的在浏览器上显示一段UUID优惠码 ,可以看到在响应时,响应头输出内容十分繁琐。

控制台输出结果:

因此,在JavaEE平台上,处理TCP连接,解析HTTP协议这些繁琐的底层工作统统被扔给现成的Web服务器去做,我们只需要把自己的应用程序运行在Web服务器上即可。
为了实现这一目的,JavaEE提供了Servlet API,我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,来实现底层功能。
简单来讲,一个Web App就是由一个或多个Servlet组成的,每个Servlet通过注解说明自己能处理的路径:
- @WebServlet("/hello.do")//所有的请求路径必须以"/"开头
- public class HelloServlet extends HttpServlet{
- ...
- }
接下来就要根据请求方式来重新父类方法:

在通过一个URL路径发起对一个Servlet请求的过程中,其本质是在调用执行Servlet实例的doXXX()方法。
-
- import java.io.IOException;
-
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- @WebServlet("/home.do")
- public class Homeservlet extends HttpServlet{
-
- //1.实例化
- //调用构造方法、创建Homeservlet实例
- public Homeservlet() {
- System.out.println("1.Homeservlet实例被创建");
- }
-
- //2.初始化
- //重写HttpServlet父类的init()方法
- //通过实例自动调用init()方法
- @Override
- public void init() throws ServletException {
- System.out.println("2.Homeservlet实例初始化");
- }
-
- //3.服务
- //通过实例调用父类(HttpServlet)的service()方法
- //service()方法会根据请求的方法调用子类重写的doGet()或doPost()方法
- //如果子类没有重写相应的方法,则调用父类的该方法,响应405
-
- //根据请求方式的不同,调用不同的请求方法
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- System.out.println("被GET请求了");
- }
-
- //4.销毁
- //调用destroy()方法
- @Override
- public void destroy() {
- System.out.println("Homeservlet实例被销毁");
- }
-
- //生命周期1实例化、2初始化、3服务、4销毁
- }
我们运行以上代码,并且请求/home.do路径,最后停止服务器。运行结果为:

通过以home.do为例,总结到:
Servlet的生命周期:指Servlet实例创建和使用的过程。
一个生命周期包括:实例化、初始化、服务、销毁。
Servlet请求的路径,查找该Servlet的实例。如果实例不存在,则通过调用构造方法,完成Servlet实例的创建。Servlet的实例,调用init()方法,执行初始化的逻辑。Servlet的实例,调用service()方法,如果子类没有重写该方法,则调用HttpServlet父类的service()方法,在父类的该方法中进行请求方式的判断,并调用响应的doXXX()方法: - 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);
- }
- }
-
- } else if (method.equals(METHOD_HEAD)) {
- long lastModified = getLastModified(req);
- maybeSetLastModified(resp, lastModified);
- doHead(req, resp);
-
- } else if (method.equals(METHOD_POST)) {
- doPost(req, resp);
-
- } else if (method.equals(METHOD_PUT)) {
- doPut(req, resp);
-
- } else if (method.equals(METHOD_DELETE)) {
- doDelete(req, resp);
-
- } else if (method.equals(METHOD_OPTIONS)) {
- doOptions(req,resp);
-
- } else if (method.equals(METHOD_TRACE)) {
- doTrace(req,resp);
-
- } else {
- //
- // Note that this means NO servlet supports whatever
- // method was requested, anywhere on this server.
- //
-
- String errMsg = lStrings.getString("http.method_not_implemented");
- Object[] errArgs = new Object[1];
- errArgs[0] = method;
- errMsg = MessageFormat.format(errMsg, errArgs);
-
- resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
- }
- }
如果子类重写
doXXX()方法,则调用子类重写后的doXXX()方法;如果子类没有重写doXXX()方法,则调用父类的doXXX()方法,在父类的方法实现中,返回一个405状态码的错误页面。405状态码:代表请求的方式服务器不提供支持。
destroy()方法。