栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java Web 基础 四】Servlet简介、执行流程和生命周期

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Java Web 基础 四】Servlet简介、执行流程和生命周期

上文提到项目中有 Servlet 和 JSP 两个类型的文件,其中 JSP 是一种特殊的 Servlet。接下来我们依次了解 Servlet、JSP,再从 Tomcat 服务器角度来看请求是如何被处理的。本文先介绍 Servlet 的执行机制。

Servlet 简介

静态网站的出现解决了全球不同地方的人无法快速交流的问题,但静态网站对应的静态资源都必须是事先存在的。比如我发布了一篇文章,想要立马在网站上看到是做不到的,必须编辑网站对应的html,将网站链接添加在html中才可以看到。为了实现这种动态交互,JAVA EE 在出现时就提出了 Servlet,用来实现动态网站。

Servlet 是运行在支持 Servlet 规范、能解释 Servlet 的 web 服务器上的 Java 类。那Servlet 是怎么实现动态的呢?

在介绍之前先要说一下 JavaEE。Java EE 在设计之时就为了解决 web 交互问题提出了分层思想,每层有很多组件。并且规定组件不能直接对外提供服务,必须增加容器层,组件部署到容器上,由容器完成对组件的管理、与外界的交互。
Servlet 就是 Java EE 提出的一个组件,它要提供功能就需要有 Servlet 容器(管理 Servlet 的生命周期),而 Servlet 容器 也是 web 服务器(比较常用的 web 服务器是 tomcat)的一个扩展功能。由此服务器端就形成了以 Servlet 为中心的三层:Servlet、Servlet 容器、web 服务器。web 服务器与客户端的交互是通过请求/响应模型完成。

Servlet 实现动态交互


接下来具体说下如何实现整个交互过程、如何完成动态网站?

  1. web 浏览器发送 HTTP 请求到 web 服务器
  2. web 服务器将请求移交给 Servlet 容器
  3. Servlet 容器根据 Servlet 配置和请求路径决定要处理的 Servlet 实例,将请求分发给该实例
  4. Servlet 是有业务逻辑的,会根据不同的请求逻辑生成不同的响应页面(虽然一开始页面是动态资源,但 Servlet 处理结束时页面内容是固定的,就是一个静态资源;也就是 Servlet 的执行会将动态资源转换为静态资源)
  5. Servlet 处理完毕,Servlet 容器刷新响应,将控制权移交给 web 服务器
  6. web 服务器将响应以静态资源的形式返回给浏览器
  7. 浏览器解析静态资源并展示(浏览器只能解析静态资源)

这里的整个交互过程只是一个规范,毕竟JAVA EE 本身就是一个规范,具体的交互细节取决于不同的 web 服务器。后面会针对具体的 web 服务器 Tomcat 介绍一些交互细节,比如 web 服务器是怎么把请求转交给 Servlet 容器的,是原封不动的把浏览器请求转交还是进行了处理?这些都会进行介绍。

创建第一个 Servlet(基于 Tomcat 服务器) 创建 Servlet ,继承自 HttpServlet

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}
根据需要实现 doGet 或 doPost 方法

比如我们现在要实现 get 方法,方法体内返回一个一句话 my first servlet!,则代码为:

public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("my first servlet!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
注册 Servlet

有两种方式可以注册 Servlet,一种是配置,一种是注解。

配置文件方式注册 Servlet

在 web.xml 中添加 Servlet 的两个配置信息:servlet和servlet-mapping。




    
    
        
        FirstServlet
        
        com.demo.servlet.FirstServlet
    
    
        
        FirstServlet
        
        /firstServlet
    

注解方式注册 Servlet

为了减少配置文件,从 Servlet 3.0 开始就提出了@WebServlet注解实现 Servlet 的注册,主要使用到 name 和 value两个属性,分别对应配置文件方式中servlet下的servlet-name、servlet-mapping下的url-pattern。在项目部署时,Servlet 容器就会处理该注解。

@WebServlet(name = "FirstServlet", value = "/firstServlet")
public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 2. 重写需要的 get 或 post 方法
        System.out.println("处理 get 请求");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("my first servlet!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
访问 Servlet

启动项目,请求路径http://localhost:8080/web/firstServlet。Servlet 被成功访问。

Servlet 执行流程

当我们通过浏览器请求 Tomcat 上的 Servlet 时整个过程什么样的呢?

  1. 浏览器发起 get 请求 http://localhost:8080/web/firstServlet
  2. Tomcat(web服务器) 接收请求,转交给 Servlet 容器
  3. Servlet 容器根据请求路径 /firstServlet ,从 Servlet 配置信息中确定要请求的 Servlet 实例,也就是 FirstServlet。根据请求方法确定是 FirstServlet 的 get 方法。
    其中根据路径http://localhost:8080/web/firstServlet定位 Servlet 实例和方法的具体过程为:
    a. ip 地址 localhost 确定服务器
    b. 端口号 8080 确定进程,也就是 Tomcat
    c. 项目上下文 /web 确定项目
    d. 资源路径 /firstServlet 确定 Servlet 实例
    e. 请求方法确定 Servlet 实例的方法
  4. Servlet 容器判断是有存在 FirstServlet 的实例对象,若存在直接将请求转发;否则先加载、实例化、初始化 FirstServlet对象,然后转发。
  5. FirstServlet 的 get 方法处理请求
  6. FirstServlet请求结束,Servlet 容器刷新响应数据,控制权移交给 Tomcat(web服务器)
  7. Tomcat(web服务器)将结果响应给浏览器
  8. 浏览器解析静态资源,页面显示 my first servlet!
Servlet 生命周期

介绍 Servlet 执行流程时有涉及 Servlet 的生命周期,这里完整的介绍一次。上文提到,Servlet 的生命周期是由 Servlet 容器管理的,包括以下四阶段:

  1. 加载和实例化。当 Servlet 容器刚刚启动、或者请求的 Servlet 实例不在内存中时,Servlet 容器会加载 Servlet 的类并实例化。该方法一般只会执行一次。
  2. 初始化。在 Servlet 被实例化后,Servlet 容器会请求 init()方法初始化 Servlet,并将ServletConfig对象作为参数传入。每个 Servlet 实例都有一个ServletConfig对象。只有初始化成功, Servlet 才可以对外提供服务。该方法一般只会执行一次。
  3. 处理请求。当 Servlet 容器收到对这一 Servlet 的请求时,会调用该对象的service()方法,并将请求和响应对象作为参数传入。在Servlet的子类 HttpServlet中,将请求根据请求方法类型又增加了几个方法:doGet()、doPost()…。同时在service()方法中根据请求方法类型转发到具体的方法中。该方法可以被多次请求。
  4. 销毁。当 Servlet 容器停止服务,destory()方法会被请求以释放资源。
Servlet 实例化时机

刚刚说到,当 Servlet 容器刚刚启动、或者请求的 Servlet 实例不在内存中时,Servlet 容器会加载 Servlet 的类并实例化。也就是 Servlet 会在两种情况下被实例化:容器启动时、第一次请求到来时。这是通过启动参数配置的。具体看下如何配置。

配置文件方式设置 Servlet 实例化时机

web.xml 文件 servlet 中通过属性 load-on-startup 设置是否在 Servlet 容器启动时创建并初始化这个 Servlet实例。负数表示第一次请求时才会被实例化;非负数则在容器启动时被实例化,且值越小越早被实例化,越晚被销毁。默认在第一次请求时被实例化。




    
    
        
        FirstServlet
        
        com.demo.servlet.FirstServlet
        1
    
    
        
        FirstServlet
        
        /firstServlet
    

注解方式设置 Servlet 实例化时机

@WebServlet注解中通过参数loadOnStartup设置实例化时机。取值含义与上文一致。

@WebServlet(name = "FirstServlet", value = "/firstServlet", loadOnStartup = 1)
public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 2. 重写需要的 get 或 post 方法
        System.out.println("处理 get 请求");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("my first servlet!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
一个实例化时机的小例子

现有有HelloServlet、FirstServlet两个类,启动项load-on-startup 的值分别为0、1,则 Servlet 容器启动时调用顺序为:

Connected to server
HelloServlet 构造函数
HelloServlet init
FirstServlet create
FirstServlet init

容器销毁时调用顺序为:

FirstServlet destroy
HelloServlet destroy
总结

JAVA EE 提出 Servlet 的目的就是为了让开发人员聚焦业务逻辑,不必关系过多细节。比如浏览器和服务器如何建立链接、服务器如何接受请求、怎么找到要处理的 Servlet 实例、Servlet 处理的结果如何通知浏览器,这些其实 Servlet 容器、web 服务器都帮我们解决了【后面会简单介绍下 tomcat 的运行机制,敬请期待】,具体来说就是 Tomcat(Tomcat 既充当了 web 服务器,又充当了 Servlet 容器) 都实现了。我们只需要实现 Servlet 就可以了。
而对于 Servlet 来说,刚刚学习的人学会如何创建就可以了,有兴趣的可以了解下 Servlet 容器是如何管理 Servlet 的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/993080.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号