WD
Classnote Docs课程课件
05

05 Servlet基础

学习目标:

  • 理解 Servlet 在 Java Web 体系中的定位,并说清它与 HTTP、Tomcat、Web 应用之间的关系
  • 掌握 Web 应用标准目录结构与 Maven Web 工程目录结构的对应关系
  • 能在 IDEA 中完成 Tomcat 配置、项目部署与基础访问验证
  • 掌握 HttpServlet 的开发方式、请求分发机制与常见注解配置
  • 能解释 Servlet 生命周期、loadOnStartup 与单例多线程模型带来的影响
  • 能区分 ServletConfigServletContext 的职责,并完成基础案例

本章重点:

  • Servlet 到底解决什么问题,以及它为什么必须运行在容器中
  • @WebServlet、URL-pattern、doGet()doPost() 这些核心开发入口
  • 生命周期:init()service()destroy() 的执行时机
  • ServletConfigServletContext 的使用边界
  • 404、500、乱码、线程安全等高频问题的定位方式
01 / Section

1. 前置知识准备

  • 已理解 HTTP 请求与响应的基本结构
  • 已完成 Tomcat 的安装、启动与基础部署
  • 已具备 Java 面向对象基础:类、继承、接口、多态
  • 已了解注解基本语法,如 @interface@Target@Retention

如果你对 Tomcat 的目录结构、部署方式和 URL 映射还不熟悉,建议先回看上一章《Tomcat服务器详解》,再学习本章。

02 / Section

2. Servlet 在 Java Web 中的定位

1.1 为什么会出现 Servlet

仅靠静态资源,服务器只能“把现成文件返回给浏览器”。

但真实业务通常需要:

  • 根据用户输入动态生成内容
  • 从数据库读取数据后再响应
  • 做登录校验、权限控制、表单处理
  • 根据不同 URL 执行不同业务逻辑

这时就需要一类运行在服务器端、可以接收请求并生成响应的程序。Servlet 就是 Java Web 中最早、最基础的这类组件。

1.2 Servlet 到底是什么

Servlet = Server + Applet,可以理解为“运行在服务器端的小程序”。

更准确地说:

  • Servlet 是一个 Java 类
  • 它不是独立运行的主程序
  • 它必须运行在 Web 容器中,例如 Tomcat
  • 它的任务是接收 HTTP 请求、处理业务、返回 HTTP 响应

可以用下面这条链路理解:

text
浏览器 -> HTTP请求 -> Tomcat -> Servlet -> 业务处理 -> HTTP响应 -> 浏览器

1.3 Servlet 与静态资源、动态资源

类型 处理方式 例子
静态资源 服务器直接读取并返回 HTML、CSS、JS、图片
动态资源 服务器程序参与处理后再生成内容 Servlet、JSP、接口返回数据

Servlet 的核心价值就在于:它让服务器能“根据请求动态做事”,而不只是返回文件。

1.4 Servlet 与后续课程的关系

在 Java Web 学习路径中,Servlet 不是孤立的一章,而是后续内容的基础:

text
HTTP -> Tomcat -> Servlet -> Request/Response -> 会话技术 -> Filter/Listener -> MVC

你后面学到的请求参数、响应输出、Cookie、Session、过滤器,最终都要落回 Servlet 所在的运行环境中。

本章小结

本章核心概念:Servlet 是运行在 Web 容器中的 Java 类,用来处理 HTTP 请求并生成动态响应。

你现在应该掌握

  • Servlet 不是独立程序,而是容器托管组件
  • Tomcat 负责接收请求并把请求分发给 Servlet
  • Servlet 是后续 Java Web 各章节的基础入口
03 / Section

3. Web 应用目录与运行方式

2.1 标准 Web 应用目录结构

一个典型 Web 应用的标准结构如下:

diagram
WebRoot/ html、css、js、images 等静态资源 META-INF/ WEB-INF/ classes/ lib/ web.xml
WebRoot/
├── html、css、js、images 等静态资源
├── META-INF/
└── WEB-INF/
    ├── classes/
    ├── lib/
    └── web.xml

其中最重要的是 WEB-INF/

  • 浏览器不能直接访问 WEB-INF 下的内容
  • 编译后的 .class 文件通常放在 WEB-INF/classes
  • 依赖 jar 包通常放在 WEB-INF/lib
  • web.xml 是传统 Web 应用的配置文件

下图可以帮助你直观看懂:哪些资源位于 Web 根路径下可以直接访问,哪些资源进入 WEB-INF 后会受到保护。

Web 应用目录中 WEB-INF 受保护资源示意图
Web 应用目录中 WEB-INF 受保护资源示意图

2.2 Maven Web 工程目录结构

实际开发中,我们更常见的是 Maven Web 工程:

diagram
project/ pom.xml src/ main/ java/ resources/ webapp/ WEB-INF/ 静态资源 test/
project/
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   ├── resources/
    │   └── webapp/
    │       ├── WEB-INF/
    │       └── 静态资源
    └── test/

它与标准 Web 结构的对应关系如下:

Maven 目录 部署后位置 说明
src/main/java WEB-INF/classes Java 源码编译后输出到这里
src/main/resources WEB-INF/classes 配置文件等资源会被复制到这里
src/main/webapp Web 根目录 HTML、CSS、JS、图片等会直接发布
pom.xml 中依赖 WEB-INF/lib 依赖 jar 会被放到应用运行时目录

如果你总觉得 “Maven 目录”和“最终部署后的 Web 目录”对不上,可以结合下面这张图一起记:

Maven Web 工程目录与最终 Web 目录映射示意图
Maven Web 工程目录与最终 Web 目录映射示意图

2.3 IDEA 中部署 Web 项目时发生了什么

IDEA 配合 Tomcat 运行 Web 项目时,本质上做了三件事:

  1. 编译 Java 源码
  2. 按 Web 应用结构组装输出目录
  3. 把输出目录映射给 Tomcat 访问

常见配置步骤如下:

  1. Run -> Edit Configurations
  2. 添加 Tomcat Server -> Local
  3. 配置 Tomcat Home
  4. Deployment 中添加 war exploded
  5. 设置 Application Context

其中第 4 步特别容易选错。对 Maven Web 项目来说,通常应该选择 war exploded,这样 Tomcat 访问到的是“展开后的可运行目录结构”,更符合我们调试 Servlet、静态资源和 WEB-INF 的课堂场景。

IDEA 中 Tomcat Deployment 需要选择 war exploded
IDEA 中 Tomcat Deployment 需要选择 war exploded

如果你继续追问 “IDEA 到底把哪些内容放进了这个可部署结构里”,可以看下面这张图。它对应的正是我们前面说的那三部分:

  • src/main/javasrc/main/resources 编译后进入 WEB-INF/classes
  • 依赖进入 WEB-INF/lib
  • src/main/webapp 作为 Web 资源目录进入最终输出
IDEA Artifact 结构与 WEB-INF/classes、Web Resource Directory 对应关系
IDEA Artifact 结构与 WEB-INF/classes、Web Resource Directory 对应关系

其中 Application Context 决定访问路径前缀。

例如:

text
Application Context = /demo

那么访问地址通常就是:

text
http://localhost:8080/demo/hello

这里的 URL 并不是“随便写的字符串”,它和 Tomcat 中的应用路径、资源路径是对应起来的。先看下面这张图,建立对 docBase、上下文路径和资源路径关系的整体印象:

URL、docBase 与资源路径对应关系示意图
URL、docBase 与资源路径对应关系示意图

如果把视角再放回到 Tomcat 服务器本身,可以进一步理解:

  • webapps 下的目录天然会形成可访问应用
  • ROOT 对应访问 /
  • 其他目录名通常对应自己的上下文路径
  • 通过 conf/Catalina/localhost/*.xml 配置 docBase 时,本质上是在把某个访问路径映射到指定磁盘目录
Tomcat 中 webapps、ROOT 与 docBase 映射关系示意图
Tomcat 中 webapps、ROOT 与 docBase 映射关系示意图

2.4 目录问题为什么会导致 404

Servlet 相关的很多 404,本质上都不是“Servlet 写错了”,而是部署结构不对

常见错误包括:

  • 静态资源放错目录,导致浏览器找不到
  • Application Context 配错,访问地址少了或多了前缀
  • 类没有编译进 WEB-INF/classes
  • 依赖没打进去,导致启动失败后你误以为是 404

所以学习 Servlet 时,目录结构和部署链路必须一起掌握。

本章小结

本章核心概念:Servlet 运行是否正常,不只取决于代码,还取决于项目目录结构与部署结果是否正确。

你现在应该掌握

  • WEB-INF 是受保护目录,浏览器不能直接访问
  • Maven Web 工程和标准 Web 目录之间是一一映射关系
  • IDEA 运行 Web 项目,本质是在帮你完成编译、组装和部署映射
04 / Section

4. 第一个 Servlet:从依赖到请求分发

3.1 引入 Servlet API

在 Maven 中,Servlet API 通常这样配置:

xml
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

这里 scope 必须是 provided,原因是:

  • 编译时需要这个依赖
  • 运行时 Tomcat 已经自带 Servlet API(lib目录下的servlet.jar)
  • 如果再把它打进项目里,容易发生版本冲突

3.2 三种开发方式

Servlet 的开发方式主要有三种:

方式 说明 是否推荐
实现 Servlet 接口 最底层,方法最多 不推荐作为入门写法
继承 GenericServlet 屏蔽部分模板代码 一般了解即可
继承 HttpServlet 适合 HTTP 请求处理 推荐

在 Web 开发里,绝大多数情况下都应该直接继承 HttpServlet

3.3 最小可运行示例

java
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;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/plain;charset=UTF-8");
        resp.getWriter().write("Hello Servlet");
    }
}

访问:

text
http://localhost:8080/应用上下文/hello

如果页面能看到 Hello Servlet,说明整个链路已经通了。

3.4 service()doGet()doPost() 的关系

初学 Servlet 时,一个最关键的问题是:

浏览器发请求之后,到底是哪个方法被调用?

答案是:先到 service(),再由 service() 分发到 doGet()doPost() 等方法。

可以用简化后的伪代码理解:

java
protected void service(HttpServletRequest req, HttpServletResponse resp) {
    String method = req.getMethod();

    if ("GET".equals(method)) {
        doGet(req, resp);
    } else if ("POST".equals(method)) {
        doPost(req, resp);
    } else if ("PUT".equals(method)) {
        doPut(req, resp);
    } else if ("DELETE".equals(method)) {
        doDelete(req, resp);
    }
}

所以我们平时重写 doGet()doPost(),其实是在参与 HttpServlet 已经帮我们搭好的请求分发流程。

3.5 GET 与 POST 的基本分工

方法 常见用途 特点
GET 查询、访问页面 参数通常跟在 URL 后
POST 提交表单、提交数据 参数通常在请求体中

一个常见写法是:

java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    doGet(req, resp);
}

这表示“先统一到同一套处理逻辑”。 但要注意:只有当 GET 和 POST 的业务语义确实一致时,才适合这样写。

本章小结

本章核心概念:开发 Servlet 的推荐入口是 HttpServlet,而请求真正的分发核心在 service()

你现在应该掌握

  • 为什么 servlet-api 要用 provided
  • 为什么入门开发几乎总是继承 HttpServlet
  • GET 请求最终会走到 doGet(),POST 请求最终会走到 doPost()
05 / Section

5. @WebServlet 与 URL 映射规则

4.1 @WebServlet 常用属性

java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebServlet {
    String name() default "";
    String[] value() default {};
    String[] urlPatterns() default {};
    int loadOnStartup() default -1;
    WebInitParam[] initParams() default {};
}

最常用的几个属性是:

属性 作用
value 指定 URL 映射路径
urlPatterns value 等价
loadOnStartup 指定启动时是否提前加载
initParams 指定 Servlet 的初始化参数

4.2 valueurlPatterns

最常见写法:

java
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {}

当只写一个 value 属性时,可以省略 value =

以下写法也成立:

java
@WebServlet(value = "/hello", loadOnStartup = 1)
public class HelloServlet extends HttpServlet {}

多个路径映射到同一个 Servlet 也可以:

java
@WebServlet({"/hello", "/hi", "/greeting"})
public class HelloServlet extends HttpServlet {}

4.3 URL-pattern 四种常见形式

类型 示例 说明
精确匹配 /hello 只匹配指定路径
路径匹配 /user/* 匹配这一前缀下的路径
扩展名匹配 *.do 匹配指定扩展名
缺省匹配 / 匹配没有被其他规则处理的请求

4.4 匹配优先级

匹配优先级遵循:

text
精确匹配 > 路径匹配 > 扩展名匹配 > 缺省匹配

例如:

java
@WebServlet("/user/login")   // A
@WebServlet("/user/*")       // B
@WebServlet("*.do")          // C
@WebServlet("/")             // D
请求 URL 实际命中
/user/login A
/user/profile B
/order/list.do C
/other/path D

4.5 缺省 Servlet 与静态资源

Tomcat 内部有一个默认 Servlet,专门处理静态资源。

这意味着:

  • 浏览器访问图片、CSS、JS 等静态资源时,通常不是你自己写的 Servlet 在处理
  • 如果你自己写了 @WebServlet("/"),就可能把默认静态资源处理逻辑“截胡”

示例:

java
@WebServlet("/")
public class MyDefaultServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h1>自定义缺省处理</h1>");
    }
}

这类写法在框架内部有它的用途,但对于入门阶段来说,要先知道风险:

  • 静态资源可能访问不到
  • 所有未命中的请求都会落到这个 Servlet

本章小结

本章核心概念:Servlet 能否被访问到,本质取决于 URL 映射规则,而不是“类写没写出来”。

你现在应该掌握

  • @WebServlet 最常用的是 valueloadOnStartupinitParams
  • URL 匹配存在固定优先级,不是“谁先写谁生效”
  • @WebServlet("/") 有特殊含义,使用前必须知道它会影响静态资源处理
06 / Section

6. Servlet 生命周期与单例多线程模型

5.1 生命周期总览

Servlet 的生命周期由容器管理,不由我们手动控制。

可以用这条链路理解:

text
加载类 -> 创建实例 -> init() -> service() 多次调用 -> destroy()

5.2 各个方法的执行时机

方法 执行次数 谁调用 典型用途
构造方法 1 次 容器 创建对象
init() 1 次 容器 初始化资源
service() 多次 容器 分发请求
destroy() 1 次 容器 释放资源

理解重点:

  • init() 不是每次请求都执行
  • destroy() 也不是每次关闭浏览器都执行
  • 只有请求处理阶段,才会反复进入 service()

5.3 生命周期观察示例

java
@WebServlet(value = "/life", loadOnStartup = 1)
public class LifeServlet extends HttpServlet {

    public LifeServlet() {
        System.out.println("1. 构造方法执行");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("2. init() 执行");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        System.out.println("3. doGet() 执行");
        resp.getWriter().write("ok");
    }

    @Override
    public void destroy() {
        System.out.println("4. destroy() 执行");
    }
}

你应该在日志里观察到:

  • Tomcat 启动时,若配置了 loadOnStartup,会先执行构造和 init()
  • 每访问一次 /life,会执行一次 doGet()
  • 正常关闭容器时,才会执行 destroy()

5.4 loadOnStartup 的意义

loadOnStartup 默认是 -1,表示第一次访问时再初始化。

java
@WebServlet(value = "/demo", loadOnStartup = 1)
public class DemoServlet extends HttpServlet {}

当值大于等于 0 时:

  • Tomcat 启动阶段就会初始化这个 Servlet
  • 数字越小,优先级通常越高

适用场景:

  • 需要预加载配置
  • 需要启动时初始化缓存
  • 希望第一次访问时响应更快

5.5 为什么说 Servlet 默认是“单例多线程”

容器通常只创建一个 Servlet 实例,但会用多个线程处理不同请求。

这就意味着:

  • 局部变量一般是线程安全的
  • 成员变量可能被多个请求共享
  • 把“请求相关状态”放进成员变量是很危险的

错误示例:

java
@WebServlet("/counter")
public class CounterServlet extends HttpServlet {

    private int count = 0;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        count++;
        resp.getWriter().write("count = " + count);
    }
}

问题在于:多个请求同时进来时,count++ 不是线程安全操作。

更安全的写法:

java
import java.util.concurrent.atomic.AtomicInteger;

@WebServlet("/counter")
public class CounterServlet extends HttpServlet {

    private final AtomicInteger count = new AtomicInteger(0);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        int current = count.incrementAndGet();
        resp.getWriter().write("count = " + current);
    }
}

本章小结

本章核心概念:生命周期由容器掌控,而单例多线程模型决定了 Servlet 编码时必须注意共享状态。

你现在应该掌握

  • init()service()destroy() 的调用时机
  • loadOnStartup 会影响初始化时机
  • 不要把请求级数据随手放到 Servlet 成员变量里
07 / Section

7. ServletConfigServletContext

6.1 两者的职责差异

这是初学 Servlet 时最容易混淆的一组对象。

对象 作用域 典型用途
ServletConfig 单个 Servlet 读取当前 Servlet 的初始化参数
ServletContext 整个 Web 应用 共享全局数据、读取应用级信息

记忆方式:

  • Config 更偏“我这个 Servlet 的配置”
  • Context 更偏“整个应用的上下文”

6.2 ServletConfig 示例

java
@WebServlet(
    value = "/config",
    initParams = {
        @WebInitParam(name = "username", value = "root"),
        @WebInitParam(name = "password", value = "123456")
    }
)
public class ConfigServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        ServletConfig config = getServletConfig();

        String username = config.getInitParameter("username");
        String password = config.getInitParameter("password");

        resp.setContentType("text/plain;charset=UTF-8");
        resp.getWriter().write(username + " / " + password);
    }
}

这一组参数只服务于当前这个 Servlet,不会自动共享给其他 Servlet。

6.3 ServletContext 示例

java
@WebServlet("/put")
public class PutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ServletContext context = getServletContext();
        context.setAttribute("appName", "ServletDemo");
    }
}

@WebServlet("/get")
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        ServletContext context = getServletContext();
        Object appName = context.getAttribute("appName");
        resp.getWriter().write(String.valueOf(appName));
    }
}

这里两个 Servlet 访问到的是同一个 ServletContext

6.4 获取 ServletContext 的常见方式

java
ServletContext context1 = getServletContext();
ServletContext context2 = getServletConfig().getServletContext();
ServletContext context3 = req.getServletContext();
ServletContext context4 = req.getSession().getServletContext();

入门阶段推荐直接记住这一种:

java
ServletContext context = getServletContext();

6.5 getRealPath() 要知道但不要滥用

java
String rootPath = getServletContext().getRealPath("/");

它可以拿到 Web 应用部署后的真实路径,但你要知道两个风险:

  • 部署方式变化后,真实路径可能变化
  • 某些打包或云部署环境下,真实路径不一定稳定

因此:

  • 本地教学、演示时可以用来帮助理解目录映射
  • 真正读取配置文件时,优先考虑 classpath 或流方式,而不是死依赖真实磁盘路径

本章小结

本章核心概念ServletConfig 管“当前 Servlet 自己的配置”,ServletContext 管“整个应用共享的上下文”。

你现在应该掌握

  • 什么场景下读初始化参数该用 ServletConfig
  • 什么场景下共享数据该用 ServletContext
  • getRealPath() 能帮助理解部署路径,但不该变成唯一依赖手段
08 / Section

8. XML 配置、JSP 关系与高频问题

7.1 web.xml 配置 Servlet

虽然现代项目更多使用注解,但 web.xml 仍值得了解,因为:

  • 老项目仍然常见
  • 它能帮助你理解 Servlet 注册的本质
  • 有些配置在 XML 中更集中
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.demo.HelloServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

7.2 注解配置与 XML 配置怎么选

方式 优点 缺点 适用场景
注解配置 直观、贴近代码 配置分散在类上 新项目、教学示例
XML 配置 集中、易统一查看 不够直观 老项目、集中治理

需要特别记住的一点是:

当注解配置和 XML 配置同时存在时,通常以 XML 为准。

7.3 JSP 与 Servlet 的关系

JSP 本质上并不是“完全不同的技术”,它最终还是会被转换成 Servlet。

可以用这条链路理解:

text
hello.jsp -> 编译成 Servlet 类 -> 再由容器执行 -> 输出 HTML

所以你可以把 JSP 看成“更偏页面模板表达的 Servlet 形态”。

在现代开发里,JSP 已不再是主流重点,但理解它和 Servlet 的关系,有助于你看懂老项目。

7.4 高频问题排查表

404 类问题

现象 可能原因 优先检查
访问 Servlet 报 404 URL 写错 @WebServlet 路径、上下文路径
静态资源 404 资源目录放错 是否放在 webapp,是否被 / 映射截胡
项目根路径 404 部署失败 IDEA Deployment、Tomcat 日志

500 类问题

现象 常见原因 优先检查
NullPointerException 参数为空、对象未初始化 对象来源与执行顺序
ClassNotFoundException 依赖缺失 pom.xml、构建结果
IllegalStateException 响应已提交后继续操作 输出顺序、转发逻辑

编码问题

请求乱码:

java
req.setCharacterEncoding("UTF-8");

响应乱码:

java
resp.setContentType("text/html;charset=UTF-8");

依赖冲突问题

如果把 servlet-api 错误地打进项目里,常见症状包括:

  • NoSuchMethodError
  • ClassCastException
  • 容器启动异常

解决方向只有一句话:

确保 servlet-api 的作用域是 provided

本章小结

本章核心概念:注解和 XML 都是在“注册 Servlet”,而常见报错大多都能回到映射、部署、编码和依赖这四条主线。

你现在应该掌握

  • web.xml 注册 Servlet 的基本形式
  • JSP 最终仍会落回 Servlet 机制
  • 404、500、乱码、依赖冲突应该从哪些方向排查
09 / Section

9. 本章总复盘

8.1 一条完整主线

可以把本章内容压缩成下面这条主线:

text
浏览器发请求
    ->
Tomcat 接收并解析路径
    ->
根据 URL 映射找到 Servlet
    ->
Servlet 进入生命周期与请求分发流程
    ->
读取参数、处理业务、写出响应
    ->
必要时通过 Config/Context 读取配置或共享数据

8.2 你现在最该记住的五件事

  1. Servlet 是运行在容器中的 Java 类,不是独立启动程序
  2. 开发入口通常是继承 HttpServlet
  3. service() 负责按 HTTP 方法分发到 doGet()doPost()
  4. Servlet 默认是单例多线程模型,成员变量必须谨慎
  5. ServletConfig 管单个 Servlet,ServletContext 管整个应用

8.3 学完这一章后,下一章会自然衔接什么

学完 Servlet 后,你最自然的下一步就是:

  • 更细致地处理请求参数和响应输出
  • 学会转发、重定向、响应头设置
  • 理解 Request 与 Response 在开发中的更多用法

这正是下一章 Request & Response 要继续展开的内容。

10 / Section

10. 实战练习

<!-- 实战练习内容已分离到 practices/markdown/05-servlet-practice.md -->

建议先回看本章重点:URL 映射、生命周期、HttpServlet 开发方式、ServletContext 共享数据,再进入配套练习。 练习顺序建议按照:基础 Servlet -> 生命周期观察 -> 访问统计 -> 登录案例。 配套练习文件:content/optimized/practices/markdown/05-servlet-practice.md