Servlet 简介

Servlet 的技术定位、与 CGI 的差别、容器提供的服务。

Beginner
Key PointsServlet 用线程而不是进程处理并发:一个实例服务多个请求,因此实例字段不安全,状态必须放在方法内或 Session 里。

Servlet 技术

A servlet is a platform-independent server-side component, compiled to bytecode and runnable in any container implementing the spec. It offers a request–response model: the container turns one HTTP exchange into one method call.

  • 高效 —— 每个请求一个线程,不是每个请求一个进程
  • 便利 —— 容器解析报文、管理连接、处理编码
  • 可移植 —— 换容器不改代码
  • 健壮 —— 容器隔离故障、回收线程、复用实例

Servlet 与 CGI 的区别

Servlet
Concurrency每个请求 fork 一个进程每个请求一个线程,实例复用
Memory进程级,几十 MB 起线程级,几百 KB
Startup每次都要加载解释器只初始化一次 init()
Portability依赖平台脚本纯 Java 字节码

容器替你做的事

You almost never touch network programming in a servlet, because the container has already done it:

  1. 监听端口、接受连接、解析 HTTP 报文
  2. 把请求映射到对应的 Servlet 类
  3. 调用 init() 一次,之后并发调用 service()
  4. 管理 Session,生成并校验 JSESSIONID
  5. 应用停止时调用 destroy(),回收资源

实例变量为什么不安全

Java
@WebServlet("/count")
public class BadCounter extends HttpServlet {
    private int count = 0;              // 所有请求共享,并发下会丢更新

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        count++;                        // 读-改-写不是原子操作
        resp.getWriter().print(count);
    }
}

The container creates only one instance, and dozens of threads run count++ at once; two threads may read the same stale value and one update is lost. Keep state in an AtomicInteger, the database or the session — not in a bare instance field.

A servlet is single-instance, multi-threaded. As long as you keep per-request data out of instance fields you need no locking; when you must share mutable state, prefer AtomicXxx or concurrent collections over synchronized on the whole method.

Friends & Partners