JavaWeb之路01--Servlet

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_42267300/article/details/86773088

Java Servlet

什么是Java servlet

Java Servlet,称为小服务程序或服务连接器(简称Servlet),是一个实现了servlet接口的普通java类,在于交互式地浏览和修改数据,生成动态Web内容。

Servlet的主要作用是

  • 接受请求
  • 处理请求
  • 生成动态的web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。


最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。




Servlet的工作模式

  • 客户端发送请求至服务器
  • 服务器启动并调用 Servlet,Servlet 根据客户端请求生成响应内容并将其传给服务器
  • 服务器将响应返回客户端



Servlet的API

  • void init(ServletConfig config):初始化方法
  • void service(ServletRequest request,ServletResponse response):服务方法
  • void destroy():销毁方法
  • ServletConfig getServletConfig():获取当前servlet的配置对象
  • String getServletInfo():获取当前servlet的信息



Servlet的生命周期

Servlet接口中void init(ServletConfig config),void service(ServletRequest request,ServletResponse response),void destroy()三个方法其实就是Servlet的生命周期函数,分别代表“出生”,“工作”,“死亡”。

我们用下面代码来看看Servlet的生命周期:

public class Demo1Servlet implements Servlet {
 
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("Servlet正在初始化");
    }
 
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //专门向客服端提供响应的方法
        System.out.println("Servlet正在完成业务逻辑");
 
    }
 
    @Override
    public void destroy() {
        System.out.println("Servlet正在销毁");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
 
    @Override
    public String getServletInfo() {
        return null;
    }



我们配置好xml中映射关系,打开服务器,第一次访问该Servlet时,控制台打印出了下面的信息:
在这里插入图片描述

在我们刷新4遍浏览器,控制台信息变成了这样:
在这里插入图片描述

当我们关闭服务器时,控制台打印出了如下信息:
在这里插入图片描述

Servlet这时终于销毁了,这就是一个Servlet的完整生命周期。

用一句话说明Servlet的生命周期也就是:默认第一次请求来的时候,服务器创建servlet的对象,且调用init方法实现初始化操作,且调调用一次service方法,每当请求来的时候,服务器获取一个线程,调用service方法,完成具体的业务逻辑(编写的代码)当servlet被移除的时候或者服务器正常关闭的时候,服务器调用destroy方法实现销毁操作。



GenericServlet 抽象类

我们前面讲了Servlet接口,但当我们每次使用时那么面有些不方便:不仅有一堆方法需要实现,还需要自己手动的维护ServletConfig这个对象的引用,那么有什么办法可以解决除了这些问题呢?

这时候就要介绍一个新的类了,他就是GenericServlet抽象类,他除了service没有实现,其他的方法都实现了。

下面我们来看看GenericServlet抽象类的原码:

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
    private transient ServletConfig config;
 
    public GenericServlet() {
    }
 
    public void destroy() {
    }
 
    public String getInitParameter(String name) {
        ServletConfig sc = this.getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getInitParameter(name);
        }
    }
 
    public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = this.getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getInitParameterNames();
        }
    }
 
    public ServletConfig getServletConfig() {
        return this.config;
    }
 
    public ServletContext getServletContext() {
        ServletConfig sc = this.getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getServletContext();
        }
    }
 
    public String getServletInfo() {
        return "";
    }
 
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
 
    public void init() throws ServletException {
    }
 
    public void log(String msg) {
        this.getServletContext().log(this.getServletName() + ": " + msg);
    }
 
    public void log(String message, Throwable t) {
        this.getServletContext().log(this.getServletName() + ": " + message, t);
    }
 
    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
 
    public String getServletName() {
        ServletConfig sc = this.getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getServletName();
        }
    }
}

由于它也不是我们的重点,所以我们不再过多讲解。



HttpServlet 抽象类

有人会想GenericServlet抽象类已经很方便了,那为什么不用呢?
锵锵锵,那是因为我们的主角,HttpServlet抽象类的功能更为强大,它到底强大在哪些方面呢,下面我将一一列出。
首先我们看一下HttpServlet的声明:

public abstract class HttpServlet extends GenericServlet implements Serializable 

很明显,它继承了GenericServlet抽象类,并实现了Serializable接口。自然也就继承了GenericServlet所拥有的优点。



HttpServlet比GenericServlet强大的地方主要有以下两点:

  • 强转了两个参数HttpServletRequest和HttpServletResponse,调用了重载的service()方法
  • 获取请求方式,根据请求方式的不同调用不同的doXxx()方法

要理解第二条,首先我们来看一下HttpServlet如何实现service() 方法的:

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);
    }

可以看到,HttpServlet抽象类中,接收到ServletRequest 和ServletResponse对象时,将其强转为HttpServletRequest和HttpServletResponse类型,之所以能够这样强制的转换,是因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest对象和HttpServletResponse对象,预备使用HTTP。
之后有又调用参数为HttpServletRequest和HttpServletResponse类型的service()方法,那么这个方法又是如何实现的呢?

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

可以看出在service方法中还是没有实现任何的服务逻辑,但是却依据HttpServletRequest中的方法参数,调用以下方法之一:doGet(),doPost(),doHead(),doPut(),doTrace(),doOptions()和doDelete()。这7种方法中,每一种方法都表示一个Http方法。doGet()和doPost()是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service()方法了,只需要覆盖doGet()或者doPost()就好了。

猜你喜欢

转载自blog.csdn.net/qq_42267300/article/details/86773088