Web 服务器本身主要负责接收客户端的原始 HTTP 请求(通过网络连接),并将其初步处理。但它并不知道如何执行特定的 Java 代码来生成动态内容。这就是 Web 容器(它是 Web 服务器的一个组成部分或一个独立的组件,例如 Tomcat 既是 Web 服务器也是 Web 容器)的作用。
Web 容器知道如何加载和管理 Java Web 应用(WAR 文件),如何找到应用中的 Servlet,以及如何根据进来的 HTTP 请求将处理任务分发给对应的 Servlet。
核心的协作机制是基于 Java Servlet API 定义的一套标准接口和类。
相应的接口 (The Interfaces):
Servlet API 是 Java EE (现在是 Jakarta EE) 规范的一部分,它定义了 Web 容器和 Servlet 之间交互的契约。主要的接口和类包括:
-
javax.servlet.Servlet
接口:- 这是所有 Servlet 都必须实现的根接口(继承
GenericServlet
或HttpServlet
来间接实现)。 - 它定义了 Servlet 的生命周期方法 (
init()
,service()
,destroy()
) 和配置方法 (getServletConfig()
,getServletInfo()
)。 - 它是 Web 容器调用 Servlet 的入口。 Web 容器通过这个接口与 Servlet 实例进行通信。
- 这是所有 Servlet 都必须实现的根接口(继承
-
javax.servlet.ServletRequest
接口:- 代表客户端发来的请求。
- 提供了获取请求信息的方法,如参数、属性、输入流等。
- 这是一个通用的请求接口,与具体协议无关。
-
javax.servlet.ServletResponse
接口:- 代表服务器要发送回客户端的响应。
- 提供了设置响应状态码、头部信息、获取输出流等方法。
- 这是一个通用的响应接口,与具体协议无关。
-
javax.servlet.http.HttpServletRequest
接口:- 继承自
ServletRequest
,专门用于处理 HTTP 请求。 - 提供了更多 HTTP 特有的方法,如获取请求方法 (GET/POST)、URI、URL、Header、Cookie、Session 等。
- Web 容器会创建实现了此接口的对象,并将它传递给 Servlet 的处理方法。
- 继承自
-
javax.servlet.http.HttpServletResponse
接口:- 继承自
ServletResponse
,专门用于生成 HTTP 响应。 - 提供了更多 HTTP 特有的方法,如设置 HTTP 状态码、重定向、设置 Content-Type、获取用于写入文本或二进制数据的 Writer/OutputStream。
- Web 容器会创建实现了此接口的对象,并将它传递给 Servlet 的处理方法,Servlet 通过操作此对象来构建响应。
- 继承自
-
javax.servlet.ServletConfig
接口:- 代表 Servlet 的配置信息,在 Servlet 初始化时由容器传递给
init()
方法。 - 可以获取 Servlet 的名称以及初始化参数。
- 代表 Servlet 的配置信息,在 Servlet 初始化时由容器传递给
-
javax.servlet.ServletContext
接口:- 代表整个 Web 应用的上下文环境。
- 提供对 Web 应用级别资源的访问,如应用初始化参数、日志记录、请求分发器 (RequestDispatcher) 等。
- 它是在整个 Web 应用生命周期内都存在的对象,可以用于在不同 Servlet 之间共享信息。
协作过程:
- 部署与启动: 我们在开发过程中将包含 Servlets 的 Web 应用(通常打包成 WAR 文件)部署到 Web 容器中。容器在启动时会读取应用的部署描述符 (
web.xml
) 或扫描注解 (@WebServlet) 来发现和加载 Servlets。 - 初始化 (
init
): 当容器首次需要使用一个 Servlet 实例(或者在容器启动时配置为立即加载)时,容器会创建该 Servlet 的实例,并调用其init(ServletConfig config)
方法进行初始化,传入一个由容器创建的ServletConfig
对象。 - 接收请求: Web 服务器接收到客户端的 HTTP 请求后,如果该请求的 URL 匹配某个 Servlet 的映射规则,服务器会将请求转交给其内部的 Web 容器处理。
- 创建请求和响应对象: Web 容器根据接收到的原始 HTTP 请求数据,创建出实现了
HttpServletRequest
和HttpServletResponse
接口的 具体实现类 的对象。这些实现类是 Web 容器提供的,它们封装了原始 HTTP 请求的所有细节和用于构建响应的方法。 - 调用服务方法 (
service
/doGet
/doPost
):- 容器找到负责处理该 URL 的 Servlet 实例(容器会维护一个 Servlet 实例池,避免重复创建)。
- 容器调用该 Servlet 实例的
service(ServletRequest req, ServletResponse resp)
方法。 - 对于继承
HttpServlet
的 Servlet,其默认的service
方法会根据请求的 HTTP 方法(GET, POST 等)进一步调用对应的doGet(HttpServletRequest req, HttpServletResponse resp)
或doPost(HttpServletRequest req, HttpServletResponse resp)
方法。 - 容器将步骤 4 中创建的
HttpServletRequest
和HttpServletResponse
对象作为参数传递给 Servlet 的处理方法。
- Servlet 处理逻辑: Servlet 在其
doGet
或doPost
等方法中,利用传入的HttpServletRequest
对象获取请求信息(参数、头部等),执行业务逻辑,然后利用HttpServletResponse
对象设置响应状态码、头部,并将要返回给客户端的数据写入到响应的输出流中。 - 发送响应: 当 Servlet 的处理方法执行完毕返回后,Web 容器会接管
HttpServletResponse
对象。容器负责将该对象中包含的响应状态码、头部信息和写入到输出流中的响应体数据,格式化为标准的 HTTP 响应报文,并通过底层的网络连接发送回客户端浏览器。 - 销毁 (
destroy
): 当 Web 应用被卸载或容器关闭时,容器会调用 Servlet 实例的destroy()
方法,允许 Servlet 释放资源。
总结:
Servlet 和 Web 服务器(容器)之间的协作完全依赖于 Java Servlet API 定义的标准接口。Web 容器充当了 Servlet 的宿主环境和调用者。它接收原始的 HTTP 请求,将其封装成 HttpServletRequest
对象,创建 HttpServletResponse
对象用于构建响应,然后调用 Servlet 实例上定义好的方法(如 service
, doGet
, doPost
),并将这两个对象作为参数传递进去。Servlet 代码只需要关注如何使用这些标准接口对象来处理请求和生成响应,而无需关心底层网络通信的细节。这种标准化的接口机制确保了 Servlet 可以在任何实现了 Servlet API 的 Web 容器中运行,极大地提高了代码的可移植性。