1.servlet的执行流程
1.1 Servlet接口定义者servlet生命周期
java
init()//初始化方法,目的是创建出servlet对象
getServletConfig()//获取servlet配置信息
service(ServletRequest var1,ServletResponse var2)//进行服务
getServletInfo()//获取servlet运行信息
destroy()//销毁servlet对象
1.1.1 init() 方法
init() 方法是 Servlet 生命周期的初始化阶段,当 Servlet 容器(如 Tomcat)第一次加载 Servlet 时会调用此方法。该方法通常用于执行一次性初始化工作:
- 创建数据库连接池
- 加载配置文件
- 初始化缓存数据
- 建立网络连接
1.1.2 getServletConfig() 方法
getServletConfig() 方法用于获取 Servlet 的配置信息:
- 返回
ServletConfig对象 - 包含 Servlet 初始化参数
- 可以访问 Servlet 上下文
- 通常在
init()方法执行后调用应用场景:
1.1.3 service() 方法
service() 方法是 Servlet 的核心处理方法,负责处理客户端请求:
- 参数:
ServletRequest请求对象和ServletResponse响应对象 - 根据请求类型(GET/POST)调用相应的处理方法
- 线程安全考虑:通常不定义实例变
1.1.4 getServletInfo() 方法
getServletInfo() 提供关于 Servlet 的元信息:
- 返回字符串形式的描述信息
- 可包含版本号、作者信息等
- 主要用于管理目的
1.1.5 destroy() 方法
destroy() 方法在 Servlet 生命周期结束时调用:
- 释放占用的资源
- 关闭数据库连接
- 保存持久化数据
- 执行清理操作
1.2 GenericServlet实现了处理servlet接口当中的除了service方法 以外的所有方法
GenericServlet类是Java Servlet API中的一个通用实现类,它作为Servlet接口的抽象实现,提供了以下功能实现:
-
生命周期方法实现:
- 实现了init(ServletConfig config)方法,用于初始化Servlet配置
- 实现了destroy()方法,用于Servlet销毁时的资源释放
- 提供了无参数的init()方法作为扩展点
-
配置信息获取:
- 实现了getServletConfig()方法,返回Servlet配置对象
- 实现了getServletInfo()方法,返回Servlet描述信息
-
实用方法:
- 实现了getInitParameter()方法,方便获取初始化参数
- 实现了getInitParameterNames()方法,枚举所有初始化参数名
- 提供了log()方法用于记录日志信息
唯一未实现的是service(ServletRequest req, ServletResponse res)方法,这保留了以下特性:
- 强制子类必须实现具体的服务逻辑
- 允许开发者根据请求类型(GET/POST等)实现不同的处理方式
- 保持了对HTTP协议和其他协议实现的灵活性
1.3 HttpServlet 实现了Servlet接口当中的service方法,为了匹配Http的请求 方式,所以我们根据http的请求方式将service方法的内容用不同方法进行 实现
在实现原理上,HttpServlet 重写了 Servlet 接口的 service 方法,并将其拆分为多个针对不同 HTTP 请求方法的专用处理方法。具体实现如下:
- service 方法首先将 ServletRequest 和 ServletResponse 转换为 HttpServletRequest 和 HttpServletResponse
- 然后根据 HTTP 请求方法调用对应的处理方法:
- doGet():处理 GET 请求
- doPost():处理 POST 请求
- doPut():处理 PUT 请求
- doDelete():处理 DELETE 请求
- doHead():处理 HEAD 请求
- doOptions():处理 OPTIONS 请求
- doTrace():处理 TRACE 请求
这种设计模式的优点包括:
- 提高代码可读性和可维护性
- 使开发者能够专注于特定请求方法的业务逻辑
- 遵循了单一职责原则
示例代码结构:
java
protected void service(HttpServletRequest req, HttpServletResponse resp) {
String method = req.getMethod();
if (method.equals("GET")) {
doGet(req, resp);
} else if (method.equals("POST")) {
doPost(req, resp);
}
// 其他方法处理...
}
1.4 继承HttpServlet,并且重写doGet(),doPost()...等等方法,进行具体的实现
在Java Web开发中,Servlet是处理HTTP请求的核心组件。要创建一个自定义的Servlet,通常需要按照以下步骤实现:
- 继承HttpServlet类
- 自定义Servlet类必须继承javax.servlet.http.HttpServlet
- 例如:
java
public class MyServlet extends HttpServlet {
// Servlet实现代码
}
- 重写请求处理方法 HttpServlet提供了多个处理不同HTTP请求的方法,开发者可以根据需要重写:
- doGet()方法:处理HTTP GET请求
java
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 处理GET请求的业务逻辑
}
- doPost()方法:处理HTTP POST请求
java
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 处理POST请求的业务逻辑
}
- 其他可重写的方法:
- doPut():处理PUT请求
- doDelete():处理DELETE请求
- doHead():处理HEAD请求
- doOptions():处理OPTIONS请求
- doTrace():处理TRACE请求
- 实际应用场景示例
- 用户登录处理(POST请求):
java
protected void doPost(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 验证用户凭证...
}
- 数据查询接口(GET请求):
java
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
String id = request.getParameter("id");
// 查询数据库...
response.getWriter().write(jsonData);
}
2.tomcat的执行流程

-
请求发起 客户端通过
http://ip:8080/xxx/xxx发送 HTTP 请求,服务器的网卡已注册 8080 等端口,等待请求连接。 -
BIO 阻塞监听与连接 服务器通过BIO(阻塞式 IO) 监听 Socket 连接:
- 当请求到达时,建立 Socket 通信 "管道";
- 打开
InputStream输入流,读取请求数据。
-
请求数据解析服务器解析输入流中的请求数据,提取关键信息:
- 来源 IP、端口、编码;
- Cookie、请求路径(如
/my/)、请求类型(如get)等。
-
匹配 Servlet 处理器 Tomcat 根据请求路径(如
/my/login),在 "Servlet 容器" 中匹配对应的 Servlet 对象:- 比如
/my/login对应loginServlet对象,/my对应MyServlet对象。
- 比如
-
执行 Servlet 方法 根据请求类型(
get/post),调用对应 Servlet 的方法:- 若为
get请求,调用MyServlet的doGet(),生成response响应信息; - 若为
post请求,调用对应 Servlet 的doPost()。
- 若为
-
响应返回 打开
OutputStream输出流,通过 Socket 管道将response响应数据返回给客户端。
2.1 阻塞方式
2.1.1. BIO (Blocking I/O) 阻塞式I/O
BIO是最传统的I/O模型,其特点是:
- 采用同步阻塞方式处理I/O操作
- 每个连接需要一个独立的线程处理
- 当没有数据可读时,线程会被阻塞,直到数据到达
- 实现简单直观,但资源消耗大
典型应用场景:
- 传统的Socket编程
- 连接数较少的客户端/服务器应用
- 需要简单实现的场景
示例代码结构:
java
ServerSocket server = new ServerSocket(8080);
while(true) {
Socket socket = server.accept(); // 阻塞等待连接
new Thread(() -> {
InputStream in = socket.getInputStream();
// 处理数据...
}).start();
}
2.1.2. NIO (Non-blocking I/O) 非阻塞I/O
NIO提供了非阻塞的I/O操作方式:
- 基于事件驱动模型(Selector)
- 单线程可以处理多个连接
- 当没有数据可读时,线程不会被阻塞
- 需要更复杂的编程模型
核心组件:
- Channel:数据通道
- Buffer:数据缓冲区
- Selector:多路复用器
典型应用场景:
- 高并发服务器应用
- 需要处理大量连接的场景
- 如Netty、Tomcat等框架底层实现
工作流程:
- 注册感兴趣的事件到Selector
- 调用select()方法检查就绪的通道
- 处理就绪的事件
- 重复上述过程
2.1.3. AIO (Asynchronous I/O) 异步I/O
AIO是真正的异步非阻塞I/O:
- 操作系统完成I/O操作后通知应用程序
- 不需要应用程序主动检查状态
- 回调机制处理完成事件
- 编程模型最复杂
实现方式:
- 基于操作系统提供的异步I/O接口
- 在Linux上主要通过epoll实现
- Windows通过IOCP实现
典型应用场景:
- 超高并发服务器
- 需要极致性能的场景
- 如高性能代理服务器、消息队列等
示例代码结构:
java
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
server.bind(new InetSocketAddress(8080));
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel client, Void attachment) {
// 处理连接完成
}
@Override
public void failed(Throwable exc, Void attachment) {
// 处理错误
}
});
2.1.4. 三种模型对比
| 特性 | BIO | NIO | AIO |
|---|---|---|---|
| 阻塞方式 | 完全阻塞 | 非阻塞 | 完全非阻塞 |
| 线程模型 | 一连接一线程 | 单线程多连接 | 回调机制 |
| 复杂度 | 简单 | 中等 | 复杂 |
| 吞吐量 | 低 | 高 | 最高 |
| 适用场景 | 低并发 | 高并发 | 超高并发 |
| 资源消耗 | 高(线程多) | 中等 | 低 |
3自定义tomcat如何实现原理

3.1 启动初始化阶段
-
扫描与收集 Servlet 信息
- 扫描项目目录下所有 Servlet 文件,获取其全路径名;
- 读取 Servlet 类中
@WebServlet注解的配置(即 Servlet 的访问路径)。
-
构建 Servlet 容器(HashMap)
- 容器的
key是 Servlet 的访问路径; - 容器的
value是对应的Servlet 对象(通过全路径名实例化生成)。
- 容器的
3.2 请求处理阶段
-
接收前端请求利用 Socket 打开输入流,获取请求信息;处理完成后通过输出流返回响应。
-
封装请求对象 创建
HttpServletRequest对象,将请求信息(路径、参数等)全部封装到该对象中。 -
匹配 Servlet 或静态资源
- 以请求路径为
key,判断 Servlet 容器中是否存在对应对象:- ✅ 存在 :调用该 Servlet 对象的对应方法(如
doGet/doPost); - ❌ 不存在 :判断请求是否为静态资源(HTML/CSS/ 图片等):
- ✅ 是静态资源:返回对应静态文件;
- ❌ 不是:返回 404 错误。
- ✅ 存在 :调用该 Servlet 对象的对应方法(如
- 以请求路径为
-
封装响应并返回 创建
HttpServletResponse对象,封装处理结果,通过 Socket 输出流返回给前端。
