servlet执行详解

个人博客地址:
http://xiaohe-blog.top

文章目录

  • 1. servlet 简述
  • 2. 第一个servlet程序
  • 3. Servelt 生命周期
    • 3.1 实例化
    • 3.2 初始化
    • 3.3 service
    • 3.4 销毁
    • 3.5 生命周期总结
  • 4. 适配器设计模式
  • 5. HttpServlet

1. servlet 简述

servlet说实在点就是个接口,浏览器发送请求给Tomcat(服务器),若是这个请求正好对应了servlet实现类的请求路径,Tomcat就会使用它来响应浏览器,这也就是request(请求)、response(响应)了。

servlet执行详解_第1张图片

servlet有5个方法,其中service是最重要的,也是我们接下来学习的重点。它的实现类也主要实现它来完成响应工作。

service方法

void service(ServletRequest var1, ServletResponse var2){}

service有两个参数,ServletRequest中带着请求的信息,例如一个学生管理系统你想删除学生,ServletRequest就会给你你想删除的学生的学号;ServletResponse中带着响应的信息,就像点击删除后你想告诉用户删除成功没。

其他四个方法中没有这两个参数,也就意味着它们无法与浏览器交互,只负责servlet中的一些初始化、get方法、销毁servlet等等。

所以在实现Servlet接口时其他方法不用管,只需要重写service方法来实现功能就好。

2. 第一个servlet程序

在配置文件web.xml中配置 :

<servlet>
     <servlet-name>myServletservlet-name>
    
     <servlet-class>com.MyServletservlet-class>
servlet>
<servlet-mapping>
      <servlet-name>myServletservlet-name>
     
      <url-pattern>/myServleturl-pattern>
servlet-mapping>

在服务器启动时 :点击这个Edit
servlet执行详解_第2张图片
servlet执行详解_第3张图片

在前端中 :

servlet执行详解_第4张图片

在java类中 :

public class MyServlet implements Servlet {
 
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {}

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
        throws ServletException, IOException {
        // 在控制台打印输出语句
        System.out.println("MyServlet --> service");
    }

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

    @Override
    public void destroy() {}
}

再点击对应链接后控制台就会打印 “MyServlet --> service”。

3. Servelt 生命周期

什么是生命周期 ?

  • servlet对象什么时候被new?创建几个?
  • servlet中的方法执行顺序 ?
  • servlet什么时候销毁 ?

这些都是由服务器决定的。服务器决定它们什么时候活,什么时候死。

3.1 实例化

想要Tomcat创建servlet实现类,就必须让Tomcat知道他在哪,这也就是为什么要在web.xml配置servlet实现类的全限定类名 :

<servlet>
     <servlet-name>myServletservlet-name>
    
     <servlet-class>com.MyServletservlet-class>
servlet>
<servlet-mapping>
      <servlet-name>myServletservlet-name>
     
      <url-pattern>/myServleturl-pattern>
servlet-mapping>

一个程序中势必有很多servlet实现类,Tomcat将他们放在内部HashMap中统一管理,前端发送请求时去map中寻找相应的servlet,调用它完成响应。如果我们平时写好servlet后忘记配置了,Tomcat就不会将它放在map容器中,自然就不会调用它。

servlet执行详解_第5张图片

那么Tomcat什么时候创建servlet对象呢?

服务器启动并不会立即创建servlet对象,我们在servlet的无参构造方法中添加输出语句,启动服务器时并不会立即执行输出语句。

服务器启动只会读取web.xml文件,将里面你配置的所有servlet连同它的请求路径加载到上述所说的“map”集合中,以待日后使用。

在浏览器发送对应请求时,才会调用无参构造创建servlet对象。

注意是无参构造,如果只有有参构造,服务器无法调用哦。

这个设计特别合理,你打开一个小说网站可能只是想读其中一个小说,那也不至于把全网所有小说都加载完吧,肯定是你点击哪一个,服务器加载哪一个。

当然我们可以使用配置信息来设置它的创建时机 ,这里不做扩展。

3.2 初始化

Servlet中有一个方法 :init(ServletConfig var),由它来完成初始化功能。Tomcat服务器实例化对应servlet后立即初始化。

默认情况下执行流程,点击链接 -> 执行无参构造 **- > **执行init。

在发送多次请求后浏览器输出如下,即使发送了多次请求,构造器和初始化方法只执行一次,而不是每一次都执行构造方法,这就证明了servlet只创建一次,以后想用直接在容器中拿,这也就是servlet的单实例特点。

单实例与单例又不同,单实例是人家可以创建,但是只由Tomcat创建一次。单例是不能new,只能创建一次。

servlet执行详解_第6张图片

为什么服务器设计时要添加一个init方法呢?init方法在构造方法之后执行并且一定会执行,那么为什么不能把init中的内容写到构造方法中呢 ?

之前我们提过,服务器调用servlet的无参构造创建对象,如果没有无参构造,就会出bug。无参构造对于整个网站来说太重要了,服务器不想让你动它,于是提供了一个init方法,你想写什么就在init中写,千万别动构造方法。

甲骨文官方也是这样说的(bushi)

3.3 service

来到重头戏service。这个方法很重要,其他方法很少用甚至用不到,但是这个方法用的很勤(相对而言)。

我们在上述MyServlet的service方法中添加输出语句,发送多次请求 :

servlet执行详解_第7张图片

可以看到,第一次发送请求后执行构造器、初始化、调用service进行响应,以后每一次发送请求只调用service方法完成请求。我们在一个网站中,多次点击登录调用的是同一个Servlet实现类,只不过调用了很多次。

3.4 销毁

在destroy方法中设置输出语句,关闭浏览器后发现没有执行destroy方法,关闭服务器才算执行了相应输出语句。而我们并没有调用destroy,可以看出 一个Servlet对象的销毁是Tomcat调用其destroy来完成的。(关闭服务器肯定要销毁servlet,不能老让它们占用资源)

3.5 生命周期总结

一个servlet的默认生命周期 :

发送对应请求后创建servlet对象,紧接着立即执行init方法,之后再发送对应请求就只执行service方法,在服务器关闭之前会调用容器中所有servlet的destroy方法销毁对象。

在servlet生命里只执行一次的方法 :构造器、初始化、销毁方法。

4. 适配器设计模式

平时我们实现Servlet接口只为了使用它的service方法,但是还要实现另外四个方法,是不是觉得太过臃肿?这么一大坨init、destroy都是无用的东西,看着也烦。

java也为我们考虑到了这一点,推出了 GenericServlet 这个类。这个类实现了Servlet接口,并且对除了service方法之外的方法都进行了默认实现,我们继承GenericServlet ,只需要写service方法就行了。
servlet执行详解_第8张图片

改版后是不是悦目很多?

servlet执行详解_第9张图片

这是一个简易的适配器设计模式 :因为Servlet接口中只需要用到service,但是有时候要用到init等其他方法,没法直接把他们删掉,于是另外搞一个类实现它的其他方法,留一个抽象的service方法给我们,当我们想要使用Servlet中其他方法时也可以直接重写。

补充 :

刚才看到GenericServlet 类中有两个init方法 :

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

}

我们知道,Tomcat调用的是有参的init(ServletConfig var),在GenericServlet 的init(ServletConfig var)中初始化了一个成员变量config,接着调用了一个空的init()方法,为什么呢?

ServletConfig包含着 本servlet的基本信息,在其他方法中还要用到。

但是Tomcat不希望碰构造方法,所以它只有在init(ServletConfig var)中初始化本类中的那个ServletConfig变量,但是万一你重写了这个init(ServletConfig var),那内部的servletConfig就无法初始化也就无法让别的方法使用,就只好提供给你一个空参的init(),反正serlvetConfig已经变成成员变量了,就不用作为形参。
servlet执行详解_第10张图片

总结 :由于不想代码冗余,官方提供了抽象类GenericServlet 实现了Servlet接口中的方法,把service设置为抽象方法供我们使用,为了能够保证GenericServlet 类中的servletConfig能够顺利赋值,官方提供了两个init,一个供服务器调用,一个供我们重写。Tomcat调用有参init,有参init中赋值servletConfig并调用了无参init,保证这两个init都能够运行。

5. HttpServlet

这个类就是我们在javaweb中日常使用的类了。

按理说 GenericServlet 已经够用了,但是 HttpServlet 是对它的扩展。HttpServlet, 类如其名,遵守Http协议,更加安全更加灵活。它提供了两个主要使用的方法 :doGet、doPost。

在html学习中我们学习了表单提交的两种方式 :get/post,是不是正好对标这两个方法?确实,前端表单如果是get方式提交数据,后端就要实现doGet方法,如果是post方法,就要实现doPost方法。

后端实现的方法要对应前端的数据提交方式

servlet执行详解_第11张图片

其实不管是doget还是doPost,最终还是调用了service,我们打开HttpServlet中的service看看 :

servlet执行详解_第12张图片

让我们还原一下具体的执行流程吧 :

我们写出以下代码 ,并将其访问路径设置为 :/myServlet:

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
		// 访问数据库,等等一系列操作
    }
}

Tomcat服务器读取配置文件,将MyServlet这个类和它的路径加载到容器中。用户访问 http://localhost:8080/项目名/myServlet时,Tomcat利用反射调用MyServlet的构造器创建对象:Servlet servlet = Class.forName(“MyServlet”) ;

Tomcat调用init(ServletConfig var)方法,调用的是MyServlet中从HttpServlet中继承下来的init(ServletConfig var),在其中为servletConfig赋值,并调用我们自己写的init(),但我们并没有写。

Tomcat调用service方法,调用 MyServlet中从HttpServlet 继承的service方法,service方法判断前端请求是get方式,于是去调用我们重写的doGet方法,完成对请求的响应。

Tomcat即将关闭,调用 MyServlet 从HttpServlet继承的destroy方法将其销毁。

下来的init(ServletConfig var),在其中为servletConfig赋值,并调用我们自己写的init(),但我们并没有写。

Tomcat调用service方法,调用 MyServlet中从HttpServlet 继承的service方法,service方法判断前端请求是get方式,于是去调用我们重写的doGet方法,完成对请求的响应。

Tomcat即将关闭,调用 MyServlet 从HttpServlet继承的destroy方法将其销毁。

上述四步代表着一个servlet的生命周期。

你可能感兴趣的:(javaweb,servlet,java,tomcat)