文章目录
Servlet
一、概述
1、Servlet
Servlet 是一种用于扩展 Java 服务器功能的技术,主要用于开发 Web 应用程序。
- Servlet 允许在 服务器端 处理 客户端请求 并生成动态内容。(包括动态网页、Web 表单处理、用户会话管理等)
- Servlet 是 Java EE 规范的一部分,通常用于处理 HTTP 请求和响应。
2、Tomcat
Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器,它实现了 Servlet 规范并提供了运行 Servlet 的环境。
- Servlet 是一个 Java 类,用于 处理客户端请求 并 生成响应。
- Tomcat 是一个 Servlet 容器 和 Web 服务器,用于运行和管理 Servlet。
Tomcat 提供了一个实现 Servlet 规范的运行时环境,允许开发者在 Web 环境中运行 Java 应用程序。
3、关系图
接收请求 --> 处理业务 --> 响应结果
Servlet
的执行及方法的调用底层都是由Tomcat
完成的。
4、Servlet 的特点
- 请求处理:
- Servlet 处理客户端(如浏览器)发送的请求,并生成响应。它可以处理表单数据、查询参数、文件上传等。
- 生命周期管理:
- Servlet 的生命周期包括 初始化、处理请求、销毁 三个阶段。Servlet 容器负责管理这些生命周期阶段。
- 多线程:
- Servlet 容器通常为每个请求创建一个新的线程来处理,因此多个请求可以并发处理。
- 状态管理:
- Servlet 可以通过会话(
HttpSession
)跟踪用户的状态和数据。
- Servlet 可以通过会话(
5、Tomcat 运行原理
-
启动过程:
当启动 Tomcat 时,它会加载并初始化一系列组件,包括:
- Connector(连接器):负责处理 客户端 与 Tomcat 之间的网络通信,它监听特定的端口,并接收客户端请求。
- Engine(引擎):是 Tomcat 处理所有请求的核心组件,它负责将请求路由到适当的虚拟主机(Host)。
- Host(主机):表示一个虚拟主机,它可以包含多个 Web 应用程序。
- Context(上下文):表示一个 Web 应用程序,它包含了 Servlet、JSP 等 Web 组件。
-
请求处理过程:
- 当客户端发送请求时,Connector 接收到请求,并将其传递给 Engine。
- Engine 根据请求的主机名找到相应的 Host,并将请求传递给 Host。
- Host 根据请求的 URL 找到对应的 Context(Web 应用程序),并将请求传递给 Context。
- Context 根据请求的 URL 找到对应的 Servlet 或 JSP,并将请求传递给相应的 Servlet 或 JSP 进行处理。
- Servlet 或 JSP 处理请求,并生成响应,然后将响应返回给客户端。
-
部署过程:
- 可以将 Web 应用程序(WAR 文件或目录)部署到 Tomcat 的 webapps 目录来添加新的 Web 应用程序。
- Tomcat 会自动检测并加载新部署的 Web 应用程序,然后启动该应用程序,并为其分配一个唯一的上下文路径。
- SpringBoot 提供了一个内嵌的 Tomcat 服务器,允许你通过简单的
java -jar
命令直接启动应用。
-
关闭过程:
- 当关闭 Tomcat 时,Tomcat 会关闭所有正在运行的 Web 应用程序,并释放占用的资源,然后停止监听端口,最终关闭自身。
二、Servlet 的生命周期
Servlet 的生命周期,指的是 Servlet对象 从 创建 到 销毁 的一个过程。
public interface Servlet {
// Servlet对象创建时,调用一次该方法
void init(ServletConfig var1) throws ServletException;
// 用户每次访问Servlet时,都会调用该方法
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
// Servlet对象销毁时,调用一次该方法
void destroy();
// 获取 ServletConfig 对象,用于获取 Servlet 的初始化参数和上下文信息。
ServletConfig getServletConfig();
// 返回 Servlet 的描述信息
String getServletInfo();
}
1、初始化
在 Servlet
对象第一次被创建时,容器会调用 init(ServletConfig)
方法进行初始化。
-
init
方法只会在Servlet
对象创建时被调用一次。 -
在
init
方法中,可以进行一些初始化操作,如读取配置文件、建立数据库连接、加载资源等。
默认情况下,init
方法是在第一次请求 Servlet 时调用的(懒加载)。如果初始化的数据很多,加载时间较长,给第一个用户的体验不好,因为要等比较久。可以通过 loadOnStartup
设置在容器启动时就实例化 Servlet
,同时执行init
方法
@WebServlet(value = "/test", loadOnStartup = 5)
public class AnnotatedServlet extends HttpServlet {}
loadOnStartup
必须是整数loadOnStartup
默认是 -1,表示第一次访问Servlet
才加载loadOnStartup
只要设置大于0,就会在容器启动时加载(数字越小,越先加载)
在 Spring Boot 中,所有的控制器在应用启动时都会被自动加载,因此不需要额外配置 loadOnStartup
。
2、请求处理
在 Servlet
初始化完成后,容器会调用 service(ServletRequest, ServletResponse)
方法 处理客户端发送的请求。
service
方法 在每次请求Servlet
时都会调用一次。service
方法 会根据请求类型(GET
、POST
等)调用相应的处理方法(如doGet()
、doPost()
等)。- 在处理完请求后,
service
方法会将响应返回给客户端。
3、销毁
在 Servlet
实例被销毁前,容器会调用 destroy()
方法进行清理工作。
destroy
方法只会在Servlet
销毁时被调用一次。destroy
方法中,可以进行一些资源释放、清理操作,如关闭数据库连接、释放内存等。
4、小结
Servlet
的生命周期由容器负责管理
- 初始化:
init()
方法在 Servlet 被加载时调用,进行初始化设置。 - 请求处理:
service()
方法处理每个请求,通常不需要直接重写,doGet()
和doPost()
等方法会被调用。 - 销毁:
destroy()
方法在 Servlet 被卸载时调用,进行资源清理。
可以通过重写 init()
、service()
和 destroy()
等方法来实现自定义的初始化、请求处理和销毁逻辑。
三、Servlet 的实现
1、GenericServlet
GenericServlet
实现了 Servlet
,重写了除 service
方法之外的其他方法。
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
public ServletConfig getServletConfig() {
return this.config;
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {}
public abstract void service(ServletRequest var1, ServletResponse var2)
throws ServletException, IOException;
public void destroy() {}
}
继承 GenericServlet
的话,就不需要实现Servlet
接口的5个方法了,只需要重写一个 service
方法就可以了。
2、HttpServlet
HttpServlet
继承于 GenericServlet
,并对service
方法进行进一步处理。
- 先将 ServletRequest 和 ServletResponse 强转为 HttpServletRequest 和 HttpServletResponse。
- 然后 根据不同的请求方式,调用对应的处理方法。
public abstract class HttpServlet extends GenericServlet {
// 将 req 和 res 强转为 HttpServletRequest 和 HttpServletResponse
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
this.service(request, response);
}
// 根据不同的请求方式,调用对应的处理方法。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals("GET")) {
this.doGet(req, resp);
} else if (method.equals("HEAD")) {
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
}
如果处理HTTP请求,可以继承 HttpServlet
,只需要重写具体的处理方法即可,例如:doGet
和 doPost
方法 。
3、自定义 Servlet
在 SpringBoot 中 定义并注册自定义 Servlet
@Component
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello from MyServlet");
}
}
@Configuration
public class ServletConfig {
@Bean
public ServletRegistrationBean<MyServlet> myServlet() {
return new ServletRegistrationBean<>(new MyServlet(), "/myServlet");
}
}