0%

DefaultServlet和JspServlet

Tomcat 中的默认 Servlet:DefaultServlet 与 JspServlet

在 Tomcat 的 conf/web.xml 配置文件中,定义了两个核心的默认 Servlet:DefaultServletJspServlet。它们是 Tomcat 处理请求的基础组件,分别负责静态资源和 JSP 页面的处理。理解这两个 Servlet 的作用和配置,有助于更好地掌握 Tomcat 的请求处理流程。

DefaultServlet:静态资源的默认处理器

DefaultServlet 是 Tomcat 的核心默认 Servlet,其 url-pattern 配置为 /,意味着当客户端请求无法匹配任何其他 Servlet 时,将由它来处理。它的主要职责是处理静态资源(如 HTML、CSS、JS、图片等),并提供基础的目录列表功能。

配置详解

conf/web.xml 中对 DefaultServlet 的默认配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value> <!-- 调试级别,0 表示关闭调试输出 -->
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value> <!-- 是否允许目录列表 -->
</init-param>
<load-on-startup>1</load-on-startup> <!-- 启动优先级:1(较高) -->
</servlet>

<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern> <!-- 匹配所有未被其他 Servlet 处理的请求 -->
</servlet-mapping>

核心功能

  • 处理静态资源
    当请求的资源是静态文件(如 index.htmlstyle.cssimage.png 等)且未被其他 Servlet 映射匹配时,DefaultServlet 会从应用的 docBase 目录(通常是 webapps/应用名)中查找并返回该文件。

  • 目录列表功能
    若请求的路径是一个目录(如 http://localhost:8080/myapp/files/),且该目录下没有欢迎文件(如 index.html),listings 参数决定是否返回目录文件列表:

    • listings=true:返回目录中所有文件的列表(类似 FTP 目录浏览)。
    • listings=false(默认):返回 403 禁止访问错误。
  • 缓存优化
    DefaultServlet 内置了静态资源缓存机制,通过设置 ExpiresCache-Control 响应头,减少重复请求,提升性能。可通过初始化参数进一步配置缓存策略,例如:

    1
    2
    3
    4
    <init-param>
    <param-name>cacheMaxAge</param-name>
    <param-value>3600</param-value> <!-- 静态资源缓存时间(秒) -->
    </init-param>
  • 支持部分请求(断点续传)
    支持 HTTP 范围请求(Range 头),允许客户端断点续传大文件(如视频、压缩包)。

实际应用场景

  • 所有未被自定义 Servlet 映射的静态资源请求,均由DefaultServlet处理。例如:
    • 访问 http://localhost:8080/myapp/js/main.js 时,若没有 Servlet 映射 *.js,则由 DefaultServlet 返回该 JS 文件。
  • 可通过覆盖应用自身的 web.xml 调整 DefaultServlet 配置(如开启目录列表、修改缓存时间)。

JspServlet:JSP 页面的专用处理器

JspServlet 负责处理所有 JSP 页面(.jsp.jspx)的请求。JSP 本质上是一种特殊的 Servlet(会被编译为 Java 类),而 JspServlet 则是这个编译和执行过程的管理者。

配置详解

conf/web.xml 中对 JspServlet 的默认配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value> <!-- 是否使用独立进程编译 JSP -->
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value> <!-- 是否在响应头中添加 X-Powered-By -->
</init-param>
<load-on-startup>3</load-on-startup> <!-- 启动优先级:3(低于 DefaultServlet) -->
</servlet>

<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern> <!-- 匹配所有 .jsp 文件 -->
<url-pattern>*.jspx</url-pattern> <!-- 匹配所有 .jspx 文件 -->
</servlet-mapping>

工作原理

JspServlet 处理 JSP 请求的流程如下:

  1. 接收请求:当客户端请求 .jsp.jspx 资源时(如 http://localhost:8080/myapp/index.jsp),请求被 JspServlet 拦截。
  2. 检查编译状态
    • 若 JSP 文件是首次被访问,或已被修改(最后修改时间晚于编译后的 class 文件),则触发编译流程。
    • 若 JSP 文件未被修改且已编译,则直接使用已生成的 class 文件。
  3. 编译 JSP
    • 第一步:将 JSP 文件转换为 Java 源文件(Servlet 代码),默认存放于 work/Catalina/localhost/应用名/ 目录下。
    • 第二步:将 Java 源文件编译为 class 字节码文件。
  4. 执行 Servlet
    构造编译后的 Servlet 实例,调用其 _jspService 方法处理请求,生成 HTML 响应返回给客户端。

关键初始化参数

JspServlet 提供了多个初始化参数,用于控制 JSP 编译和执行行为:

参数名 作用说明 默认值
fork 是否使用独立进程编译 JSP(true 表示使用,避免编译过程影响 Tomcat 主线程)。 false
xpoweredBy 是否在响应头中添加 X-Powered-By: JSP/2.3 标识。 false
compiler 指定 JSP 编译器(如 javac)。 系统默认
classdebuginfo 是否在编译的 class 文件中包含调试信息。 true
trimSpaces 是否删除 JSP 生成的 HTML 中的多余空格。 false
development 是否启用开发模式(修改 JSP 后自动重新编译)。 true

开发模式 vs 生产模式

  • 开发模式(默认):
    development=true 时,Tomcat 会自动检测 JSP 文件的修改,每次访问都会重新编译(若有更新),便于开发调试。

  • 生产模式
    部署到生产环境时,建议将 development 设为 false,并预编译所有 JSP(避免首次访问时的编译延迟):

1
2
3
4
<init-param>
<param-name>development</param-name>
<param-value>false</param-value>
</init-param>

两个默认 Servlet 的关系与请求匹配优先级

Tomcat 处理请求时,会按照 Servlet 映射的优先级匹配请求路径,规则如下:

  1. 精确匹配:优先匹配精确的 url-pattern(如 /login)。
  2. 路径匹配:匹配带有 * 的路径模式(如 /user/*)。
  3. 扩展名匹配:匹配 *.xxx 形式的模式(如 *.jspJspServlet 处理)。
  4. 默认匹配:所有未被匹配的请求,由 DefaultServleturl-pattern="/")处理。

示例

  • 请求 http://localhost:8080/myapp/login.jsp 会被 JspServlet*.jsp)匹配。
  • 请求 http://localhost:8080/myapp/css/style.css 会被 DefaultServlet 处理(无其他匹配)。
  • 请求 http://localhost:8080/myapp/user/123 若匹配自定义 Servlet 的 /user/*,则由该 Servlet 处理,否则由 DefaultServlet 处理。

自定义与优化建议

  1. 优化静态资源处理
    可通过修改 DefaultServlet 的缓存参数提升静态资源加载速度:

    1
    2
    3
    4
    <init-param>
    <param-name>cacheMaxAge</param-name>
    <param-value>86400</param-value> <!-- 缓存 24 小时 -->
    </init-param>
  2. 禁用目录列表
    生产环境务必保持 listings=false,防止目录结构暴露(安全风险)。

  3. JSP 预编译
    生产环境中,使用 Tomcat 提供的 jspc 工具预编译 JSP,避免运行时编译开销:

    1
    2
    # 预编译 myapp 应用的所有 JSP
    $CATALINA_HOME/bin/jspc -p myapp -d $CATALINA_HOME/webapps/myapp/WEB-INF/classes -v $CATALINA_HOME/webapps/myapp
  4. 覆盖默认配置
    若需在单个应用中修改配置,可在应用的 WEB-INF/web.xml 中重新定义 DefaultServletJspServlet(会覆盖全局配置)。

欢迎关注我的其它发布渠道